PHP 多线程抓取网页
PHP 利用 Curl Functions 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,受限于php语言本身不支持多线程,所以开发爬虫程序效率并不高,这时候往往需 要借助Curl Multi Functions 它可以实现并发多线程的访问多个url地址。既然 Curl Multi Function如此强大,能否用 Curl Multi Functions 来写并发多线程下载文件呢,当然可以,下面给出我的代码:
示例1:爬取内容写入文件
<?php $urls = array( 'http://mimvp.com', 'http://proxy.mimvp.com', 'http://money.mimvp.com', 'http://domain.mimvp.com', ); $save_file = './save_file.txt'; $sf = fopen($save_file, "a"); // 初始化 $mh = curl_multi_init(); foreach ($urls as $i => $url) { $conn[$i] = curl_init($url); curl_setopt($conn[$i], CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); curl_setopt($conn[$i], CURLOPT_HEADER, 0); // 将头文件的信息作为数据流输出 curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1); // 返回文件流信息, 1 - 文件; 0 - 屏幕 curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT, 60); // 设置连接超时 curl_setopt($conn[$i], CURLOPT_FILE, $sf); // 设置爬取内容写入文件 curl_multi_add_handle($mh, $conn[$i]); } // 执行 do { curl_multi_exec($mh, $active); } while($active); // 清理结束 foreach ($urls as $i => $url) { curl_multi_remove_handle($mh, $conn[$i]); curl_close($conn[$i]); } curl_multi_close($mh); fclose($sf); ?>
示例2:爬取内容先放入变量,再写入文件
<?php $urls = array( 'http://mimvp.com', 'http://proxy.mimvp.com', 'http://money.mimvp.com', 'http://domain.mimvp.com', ); $save_file = './save_file.txt'; $sf = fopen($save_file, "a"); // 初始化 $mh = curl_multi_init(); foreach ($urls as $i => $url) { $conn[$i] = curl_init($url); curl_setopt($conn[$i], CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); curl_setopt($conn[$i], CURLOPT_HEADER, 0); // 将头文件的信息作为数据流输出 curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, true); // 设置不将爬取代码写到浏览器,而是转化为字符串; 返回文件流信息, 1 - 文件; 0 - 屏幕 curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT, 60); // 设置连接超时 curl_multi_add_handle($mh, $conn[$i]); } // 执行 do { curl_multi_exec($mh, $active); } while($active); // 获得内容先存入变量,再写入文件 foreach ($urls as $i => $url) { $data = curl_multi_getcontent($conn[$i]); // 获得爬取的内容 fwrite($sf, $data); // 将内容写入文件,也可存入数据库 } // 清理结束 foreach ($urls as $i => $url) { curl_multi_remove_handle($mh, $conn[$i]); curl_close($conn[$i]); } curl_multi_close($mh); fclose($sf); ?>
curl_multi 使用步骤
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close
各函数作用:
curl_multi_init()
初始化一个curl批处理句柄资源。
curl_multi_add_handle()
向curl批处理会话中添加单独的curl句柄资源。curl_multi_add_handle()函数有两个参数,第一个参数表示一个curl批处理句柄资源,第二个参数表示一个单独的curl句柄资源。
curl_multi_exec()
解析一个curl批处理句柄,curl_multi_exec()函数有两个参数,第一个参数表示一个批处理句柄资源,第二个参数是一个引用值的参数,表示剩余需要处理的单个的curl句柄资源数量。
curl_multi_remove_handle()
移除curl批处理句柄资源中的某个句柄资源,curl_multi_remove_handle()函数有两个参数,第一个参数表示一个curl批处理句柄资源,第二个参数表示一个单独的curl句柄资源。
curl_multi_close()
关闭一个批处理句柄资源。
curl_multi_getcontent()
在设置了CURLOPT_RETURNTRANSFER的情况下,返回获取的输出的文本流。
curl_multi_info_read()
获取当前解析的curl的相关传输信息。
Maximum execution time of 30 seconds exceeded解决办法
错误提示:
Fatal error: Maximum execution time of 30 seconds exceeded in /xxx/lib/mimvp_check.php on line 35
解决办法:
报错一:内存超限
利用循环分批导入,每个循环内部开始处使用sleep(5);语句,做延迟执行,防止服务器内存同一时间占用过多,sleep数字根据实际情况修改;
每个循环内部结束地方使用 ob_flush();刷新输出缓冲
flush();将当前为止程序的所有输出发送到用户的浏览器
两者必须同时使用来刷新输出缓冲
报错二:30秒运行超时的错误(Maximum execution time of 30 seconds exceeded)
解决办法:
方法一,修改php.ini文件
max_execution_time = 30; Maximum execution time of each script, in seconds
把它设置成需要的值,例如: 600(10分钟),如果设置成0,就是永不过期。
方法二,修改php执行文件,文件开头添加一行
<? set_time_limit(0); ?>
参考推荐:
PHP curl_multi_exec执行超时的问题 (推荐)
PHP curl_multi_exec 解析一个cURL批处理句柄
curl_init()和curl_multi_init()多线程的速度比较 (推荐)
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2017-01-17 11:05:44
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
转载注明: PHP 多线程抓取网页 (米扑博客)