php多线程采集网页的解决办法 curl多线程采集
一直在使用thinkphp做项目,同样也经常进行采集!而对于物联卡来说,就更要大量的采集运营商提供的API信息,平时使用PHP单线程curl采集多个网页的时候速度特别慢,尤其是采集几十个接口的时候(电信不提供多个流量卡同时调用数据的接口,只能一个一个的查询);这个速度慢的要死要死的!于是就想到curl多线程采集的问题,最终找到几个效果还是很不错的!解决了采集运营商接口的大难题!测试了一下,采集20条数据的时间为4秒左右,比平时要快2倍了!
既然为了学习,那么先来了解下PHP curl函数信息:
PHP cURL所有函数列表:https://secure.php.net/manual/zh/ref.curl.php
以下是PHP中cURL多线程相关函数:
- curl_multi_add_handle — 向curl批处理会话中添加单独的curl句柄
- curl_multi_close — 关闭一组cURL句柄
- curl_multi_exec — 运行当前 cURL 句柄的子连接
- curl_multi_getcontent — 如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流
- curl_multi_info_read — 获取当前解析的cURL的相关传输信息
- curl_multi_init — 返回一个新cURL批处理句柄
- curl_multi_remove_handle — 移除curl批处理句柄资源中的某个句柄资源
- curl_multi_select — 等待所有cURL批处理中的活动连接
- curl_multi_setopt — 为 cURL 并行处理设置一个选项
- curl_multi_strerror — Return string describing error code
一般来说,想到要用这些函数时,目的显然应该是要同时请求多个URL,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。
步骤总结如下:
1、调用 curl_multi_init,初始化一个批处理handle
2、循环调用 curl_multi_add_handle,往1中的批处理handle 添加curl_init来的子handle
3、持续调用 curl_multi_exec,直到所有子handle执行完毕。
4、根据需要循环调用 curl_multi_getcontent 获取结果
5、调用 curl_multi_remove_handle,并为每个字handle调用curl_close
6、调用 curl_multi_close
好了,直接上函数(输入参数为url数组,返回结果为对应的网页源码数组)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
function curl_multi($urls) { if (!is_array($urls) or count($urls) == 0) { return false; } $num=count($urls); $curl = $curl2 = $text = array(); $handle = curl_multi_init(); function createCh($url) { $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $url); curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko');//设置头部 curl_setopt ($ch, CURLOPT_REFERER, $url); //设置来源 curl_setopt ($ch, CURLOPT_ENCODING, "gzip"); // 编码压缩 curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);//是否采集301、302之后的页面 curl_setopt ($ch, CURLOPT_MAXREDIRS, 5);//查找次数,防止查找太深 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在 curl_setopt ($ch, CURLOPT_TIMEOUT, 20); curl_setopt ($ch, CURLOPT_HEADER, 0);//输出头部 return $ch; } foreach($urls as $k=>$v){ $url=$urls[$k]; $curl[$k] = createCh($url); curl_multi_add_handle ($handle,$curl[$k]); } $active = null; do { $mrc = curl_multi_exec($handle, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select($handle) != -1) { usleep(100); } do { $mrc = curl_multi_exec($handle, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } foreach ($curl as $k => $v) { if (curl_error($curl[$k]) == "") { $text[$k] = (string) curl_multi_getcontent($curl[$k]); } curl_multi_remove_handle($handle, $curl[$k]); curl_close($curl[$k]); } curl_multi_close($handle); return $text; } |
函数使用:
1 2 3 4 5 6 7 8 9 10 11 |
$urls=array('http://www.21863.cn', 'http://www.baidu.com', 'http://www.baidu.com', 'http://blog.21863.cn', 'http://www.baidu.com', 'http://www.baidu.com', 'http://www.baidu.com', 'http://www.baidu.com' ); $res=curl_multi($urls); print_r($res); |
而这个多线程的采集函数怎么运用到实际的项目中,这就很简单了吧!