bizonix / rolling-curl
Rolling-Curl:PHP的一个非阻塞、非DOS多curl库
3.1.1
2017-12-11 01:19 UTC
Requires
- php: >=5.3.0
- ext-curl: *
- lib-curl: *
This package is not auto-updated.
Last update: 2024-09-28 03:31:33 UTC
README
一个用于同时获取大量资源并保持一致数量的并发连接的cURL库
作者
- Jeff Minard (jrm.cc)
- Josh Fraser (joshfraser.com)
- Alexander Makarov (rmcreative.ru)
概述
RollingCurl是curl_multi()的一个更高效实现。
curl_multi是PHP中并行处理多个HTTP请求的不错方法,但存在一些缺陷
- curl_multi的文档非常晦涩,因此很容易实现不正确或质量较差
- 大多数curl_multi示例都会将所有请求排队,然后一次性执行它们
第二个点非常重要,原因有两个
- 如果你必须等待每个请求完成,你的程序将被最长运行的请求“阻塞”。
- 更重要的是,当你同时运行大量cURL请求时,本质上你正在运行一个DOS攻击。如果你必须获取数百甚至数千个URL,你很可能会被自动DOS系统阻止。最糟糕的是,你并不是一个尊重互联网的网民。
RollingCurl通过保持最大并发请求数量并将新请求“滚动”到队列中来处理这两个问题,当现有请求完成时。当请求完成,并且其他请求仍在运行时,RollingCurl可以运行匿名函数来处理获取的结果。(如果您更喜欢,您可以选择跳过函数,并在所有请求完成后一次性处理。)
安装(通过composer)
获取composer 并将其添加到composer.json的requires部分
{
"require": {
"chuyskywalker/rolling-curl": "*"
}
}
然后
composer install
用法
基本示例
$rollingCurl = new \RollingCurl\RollingCurl(); $rollingCurl ->get('http://yahoo.com') ->get('http://google.com') ->get('http://hotmail.com') ->get('http://msn.com') ->get('http://reddit.com') ->setCallback(function(\RollingCurl\Request $request, \RollingCurl\RollingCurl $rollingCurl) { // parsing html with regex is evil (http://bit.ly/3x9sQX), but this is just a demo if (preg_match("#<title>(.*)</title>#i", $request->getResponseText(), $out)) { $title = $out[1]; } else { $title = '[No Title Tag Found]'; } echo "Fetch complete for (" . $request->getUrl() . ") $title " . PHP_EOL; }) ->setSimultaneousLimit(3) ->execute();
获取大量页面
让我们抓取Google上“curl”的第一页500个链接和标题
$rollingCurl = new \RollingCurl\RollingCurl(); for ($i = 0; $i <= 500; $i+=10) { // https://www.google.com/search?q=curl&start=10 $rollingCurl->get('https://www.google.com/search?q=curl&start=' . $i); } $results = array(); $start = microtime(true); echo "Fetching..." . PHP_EOL; $rollingCurl ->setCallback(function(\RollingCurl\Request $request, \RollingCurl\RollingCurl $rollingCurl) use (&$results) { if (preg_match_all('#<h3 class="r"><a href="([^"]+)">(.*)</a></h3>#iU', $request->getResponseText(), $out)) { foreach ($out[1] as $idx => $url) { parse_str(parse_url($url, PHP_URL_QUERY), $params); $results[$params['q']] = strip_tags($out[2][$idx]); } } // Clear list of completed requests and prune pending request queue to avoid memory growth $rollingCurl->clearCompleted(); $rollingCurl->prunePendingRequestQueue(); echo "Fetch complete for (" . $request->getUrl() . ")" . PHP_EOL; }) ->setSimultaneousLimit(10) ->execute(); ; echo "...done in " . (microtime(true) - $start) . PHP_EOL; echo "All results: " . PHP_EOL; print_r($results);
设置自定义curl选项
对于 每个 请求
$rollingCurl = new \RollingCurl\RollingCurl(); $rollingCurl // setOptions will overwrite all the default options. // addOptions is probably a better choice ->setOptions(array( CURLOPT_HEADER => true, CURLOPT_NOBODY => true )) ->get('http://yahoo.com') ->get('http://google.com') ->get('http://hotmail.com') ->get('http://msn.com') ->get('http://reddit.com') ->setCallback(function(\RollingCurl\Request $request, \RollingCurl\RollingCurl $rollingCurl) { echo "Fetch complete for (" . $request->getUrl() . ")" . PHP_EOL; }) ->setSimultaneousLimit(3) ->execute();
对于 单个 请求
$rollingCurl = new \RollingCurl\RollingCurl(); $sites = array( 'http://yahoo.com' => array( CURLOPT_TIMEOUT => 15 ), 'http://google.com' => array( CURLOPT_TIMEOUT => 5 ), 'http://hotmail.com' => array( CURLOPT_TIMEOUT => 10 ), 'http://msn.com' => array( CURLOPT_TIMEOUT => 10 ), 'http://reddit.com' => array( CURLOPT_TIMEOUT => 25 ), ); foreach ($sites as $url => $options) { $request = new \RollingCurl\Request($url); $rollingCurl->add( $request->addOptions($options) ); } $rollingCurl->execute();
更多示例可以在examples/目录中找到。
待办事项
- PHPUnit测试
- 确保PSR规范兼容性
- 修复待办事项
- 在setter上提供更好的验证
欢迎fork并提交pull request以帮助解决以上问题。 :D