PHP利用CURL实现多线程获取网页源码方法
PHP 利用 Curl 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等。
然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集数据可以利用 phpQuery类来采集数据库,
在此之外也可以用 Curl ,借助Curl 这个功能实现并发多线程的访问多个url地址以实现并发多线程抓取网页或者下载文件。
如果需要了解curl所有函数可以看这里:函数列表查看
下面是多线程使用到的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
实现步骤如下:
一般来说,使用多线程curl获取网页源码或下载图片等都是针对多个网址操作的,而不是每次都请求一次,那不如去循环curl_exec。
接下来直接放封装好的函数:
/* 多线程获取网页源码 @param array $urls @return array */ 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 (Linux; U; Android 4.4.1; zh-cn; R815T Build/JOP40D) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/4.5 Mobile Safari/533.1'); //设置头部 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批处理会话中添加单独的curl句柄 curl_multi_add_handle($handle, $curl[$k]); } $active = null; do { //运行当前 cURL 句柄的子连接 $mrc = curl_multi_exec($handle, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { //等待所有cURL批处理中的活动连接 if (curl_multi_select($handle) != -1) { usleep(100); } do { //运行当前 cURL 句柄的子连接 $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该句柄资源 curl_multi_remove_handle($handle, $curl[$k]); curl_close($curl[$k]); } //关闭cURL句柄 curl_multi_close($handle); //将数组返回 return $text; }
函数的使用示例:
<?php $arr=[ 'http://baidu.com', 'http://taobao.com', 'http://jd.com', 'http://wslmf.com' ]; $res=curl_multi($arr); var_dump($res);
到这里基本就结束了。此外,继续简单的封装了单线程curl访问(等同于file_get_contents)一样的函数:
/* 访问网站源码 @param string $url @return string */ function curl_get($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Linux; U; Android 4.4.1; zh-cn; R815T Build/JOP40D) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/4.5 Mobile Safari/533.1'); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $content = curl_exec($ch); curl_close($ch); return ($content); }
最后,大家尽可能使用curl去爬取网站,因为file_get_contents效率太低了,curl大概能提升40%
2020年2月4日更新curl伪造ip方法及可选post/get提交方式
/** * 请求html页面源码接口数据方法 * @param string $url 请求地址 * @param int 访问方式 1:post 0:get 默认 get方式 * @param string 上传文件 * @param string cookie文件 * @param bool 请求头 * @return string 数据 */ function getHtml($url, $ifpost = 0, $datafields = '', $cookiefile = '', $v = false) { // 伪造IP $xforip = rand(1, 254) . "." . rand(1, 254) . "." . rand(1, 254) . "." . rand(1, 254); $header = array("Connection: Keep-Alive", "Accept: application/json, text/javascript, */*; q=0.01", "Pragma: no-cache", "Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3", "User-Agent: Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14", 'CLIENT-IP:' . $xforip, 'X-FORWARDED-FOR:' . $xforip); // 请求头信息 $ch = curl_init(); // 使用伪造代理IP curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, $v); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); $ifpost && curl_setopt($ch, CURLOPT_POST, $ifpost); $ifpost && curl_setopt($ch, CURLOPT_POSTFIELDS, $datafields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate'); $cookiefile && curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile); $cookiefile && curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile); $r = curl_exec($ch); curl_close($ch); return $r; }
评论
帅气的孩子
回复6666