php curl_multi系列函数实现多线程抓取网页
最近几天在做一个多搜索引擎关键字排名查询工具,用于及时方便的了解关键词在各大搜索引擎的排名。
在抓取360搜索的时候,发现360搜索每页只支持显示10个搜索结果,如果想获取100个搜索结果数据,就得搜索10次,十分影响用户体验,没有人会为了查询一次关键字排名而愿意等待打开10次的网页时间。
这时我想到了用多线程做并发抓取,正好php curl的curl_multi系列函数能实现此功能。
一、curl_multi系列的函数介绍:
1. curl_multi_init:
用来初始化一个"curl_multi"句柄,然后将多个"curl_init"函数生成的"curl"句柄传递给"curl_multi"句柄;此函数不需要然后参数。
2. curl_multi_add_handle:
"curl_multi_add_handle"函数用来将"curl_init"生成的"curl"句柄添加到上面"curl_multi_init"函数生成的"curl_multi"句柄。"curl_multi_add_handle"函数的第一个参数为"curl_multi"句柄,第二个参数为"curl"句柄。
3. curl_multi_exec:
"curl_multi_exec"用于发起curl_multi请求。"curl_multi_add_handle"函数的第一个参数为"curl_multi"句柄,第二个参数是一个"引用参数",它记录未处理完成的请求数,当第二个参数值变为0时,代表所有的请求都已经处理完成(所有请求成功返回或者到达超时时间)。
4. curl_multi_info_read:
"curl_multi_info_read"函数用来读取curl_multi句柄是否有curl返回信息,如果有则返回最先的"curl返回值(数组形式)",否则返回"false",循环调用此函数,直到其返回"false";"curl_multi_info_read"的参数为"curl_mulit"句柄。
5. curl_multi_getcontent:
当所有curl句柄处理完成,这时我们就可以使用"curl_multi_getcontent"函数读取"curl"的返回内容了。"curl_multi_getcontent"的参数为"curl"句柄。
6. curl_multi_remove_handle:
读取完内容后,使用"curl_multi_remove_handle"函数从"curl_mulit"句柄中移出所有"curl"句柄。"curl_multi_remove_handle"函数的第一个参数为"curl_multi"句柄,第二个参数为"curl"句柄。
7. curl_multi_close:
"curl_multi_close"函数用于关闭"curl_mulit"句柄,释放占用的资源。"curl_multi_close"的参数为"curl_mulit"句柄。
二、curl_multi使用流程:
1、 "curl_multi_init"初始化"curl_multi"句柄;
2、 循环创建并添加"curl"句柄,并用"curl_multi_add_handle"函数将其添加到"curl_multi"句柄;
3、 使用"curl_multi_exec"发起请求,并等待所有请求处理完成;
4、 使用"curl_multi_info_read"函数读取返回值;
5、 使用"curl_multi_getcontent"函数读取返回内容;
6、 使用"curl_multi_remove_handle"函数移除curl句柄;
7、 使用"curl_multi_close"关闭curl_multi句柄。
三、下面是我使用curl_multi多线程并发抓取360搜索返回结果的代码片段:
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
52
53
54
55
56
|
#多线程并发抓取函数mfetch:
function mfetch($params=array(), $method){
$mh = curl_multi_init(); #初始化一个curl_multi句柄
$handles = array();
foreach($params as $key=>$param){
$ch = curl_init(); #初始化一个curl句柄
$url = $param["url"];
$data = $param["params"];
if(strtolower($method)==="get"){
#根据method参数判断是post还是get方式提交数据
$url = "$url?" . http_build_query( $data ); #get方式
}else{
curl_setopt( $ch, CURLOPT_POSTFIELDS, $data ); #post方式
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER["HTTP_USER_AGENT"]);
curl_multi_add_handle($mh, $ch);
$handles[$ch] = $key;
#handles数组用来记录curl句柄对应的key,供后面使用,以保证返回的数据不乱序。
}
$running = null;
$curls = array(); #curl数组用来记录各个curl句柄的返回值
do { #发起curl请求,并循环等等1/100秒,直到引用参数"$running"为0
usleep(10000);
curl_multi_exec($mh, $running);
while( ( $ret = curl_multi_info_read( $mh ) ) !== false ){
#循环读取curl返回,并根据其句柄对应的key一起记录到$curls数组中,保证返回的数据不乱序
$curls[$handles[$ret["handle"]]] = $ret;
}
} while ( $running > 0 );
foreach($curls as $key=>&$val){
$val["content"] = curl_multi_getcontent($val["handle"]);
curl_multi_remove_handle($mh, $val["handle"]); #移除curl句柄
}
curl_multi_close($mh); #关闭curl_multi句柄
ksort($curls);
return $curls;
}
#调用参数:
$keword = "360";
$page = 1;
$params = array();
for($i=0;$i<10;$i++){
$params[$i] = array(
"url"=>"http://www.so.com/s",
"params"=>array('q'=>$keyword,'ie'=>"utf-8",'pn'=>($page-1)*10+$i+1)
);
}
$ret = mfetch($params, 'GET');
print_r($ret);
|
常见错误:
1、调用curl_multi系列函数时出现如下错误:
1
|
Fatal error: Call to undefined function curl_multi_init() in 文件.php on line 行号
|
解答:1、需要php5版本才支持curl_multi系列函数;2.需要开启php curl扩展,windows: 在php.ini中把";extension=php_curl.dll"前面的分号去掉; linux:确认/etc/php.ini或者"/etc/php.d/curl.ini"中有类似"extension=curl.so"的行,并重启apache;
2、调用curl系列函数时出现如下错误:
1
|
Call to undefined function curl_init() in 文件.php on line 行号
|
解答:同上。
3、用curl抓取网页时,发现网页的中文是乱码:
解答:这是由于被抓取的网页编码与您的网页编码不一致引起的,设置"curl_setopt($ch, CURLOPT_HEADER, 1);"可以返回http头,然后从中查看到类似"Content-Type: text/html; charset=gb2312"的行,从中可以看出其编码为"gb2312"在使用$html = iconv("gb2312", "utf-8//ignore", $html); 将编码转为一致即可。
php curl_multi系列函数实现多线程抓取网页的更多相关文章
- PHP利用Curl实现多线程抓取网页和下载文件
PHP 利用 Curl 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集 数据可以利用 PHPquery ...
- 转 PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据) 通过curl_setopt()函数可以方便快捷的抓取网页(采集很方便),curl_setopt 是php的一个 ...
- PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
通过curl_setopt()函数可以方便快捷的抓取网页(采集很方便),curl_setopt 是php的一个扩展库 使用条件:需要在php.ini 中配置开启.(PHP 4 >= 4.0.2) ...
- 通过curl模拟多线程抓取网页(curl_multi_*)
curl请求多个url,以前都是使用循环来处理.最近发现可以通过curl_multi_*系列函数来模拟多线程.比对一下,发现如果请求的url只有几个,2种方案耗时差不多,但是url比较多,差距就非常明 ...
- php curl多线程抓取网页
PHP 利用 Curl Functions 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,受限于php语言本身不支持多线程,所以开发爬虫程序效率并不高,这时候往往需 要借助Cu ...
- 简单的使用php多线程抓取网页
PHP 利用 Curl Functions 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,受限于php语言本身不支持多线程,所以开发爬虫程序效率并不高,这时候往往需 要借助Cu ...
- curl模拟多线程抓取网页(优化)
通过上篇文章清楚了通过curl_multi_*函数可以一次请求多个url,但是也留下了问题,就是结果要等所有数据请求结束一起返回,才能逐个处理数据.优化代码,使先成功请求的url先返回处理结果,而不是 ...
- python多线程抓取网页信息
#!/usr/env python #-*- coding: utf-8 -*- import urllib import urllib2 import random import requ ...
- Python爬虫练习(多线程,进程,协程抓取网页)
详情点我跳转 关注公众号"轻松学编程"了解更多. 一.多线程抓取网页 流程:a.设置种子url b.获取区域列表 c.循环区域列表 d.创建线程获取页面数据 e.启动线程 impo ...
随机推荐
- Node.js使用rabbitMQ(一)
目前使用的开发环境主要还是win,所以也只是介绍在win下的rabbitMQ的使用. 一.安装rabbitMQ(Installing on Windows) 关于安装地址,参见:Installing ...
- IOS 视频流
https://github.com/kolyvan/kxmovie demo 项目
- 深入浅出HTTPS基本原理
基础知识准备:在了解HTTPS的基本原理之前,需要先了解如下的基本知识. 一.什么是HTTPS,TLS,SSL HTTPS,也称作HTTP over TLS.TLS的前身是SSL,TLS 1.0通常被 ...
- HTML5学习笔记(十二):JavaScript新增Map和Set
Map JavaScript的默认对象表示方式{}可以视为其他语言中的Map或Dictionary的数据结构,即一组键值对. 但是JavaScript的对象有个小问题,就是键必须是字符串.但实际上Nu ...
- Advanced DataStream API Low-latency Event Time Join
http://training.data-artisans.com/exercises/eventTimeJoin.html
- OpenStack大规模部署详解
https://blog.csdn.net/karamos/article/details/80130443 0.前言今年的2月22日,OpenStack发布了15个版本Ocata. 走过了7年的发展 ...
- IBM研究院找到度量安全性方法:容器与虚拟机,谁更安全?
https://zhuanlan.zhihu.com/p/40446759 虚拟机比容器更安全吗?你可能会有自己的答案,但IBM研究院发现容器的安全性与虚拟机一样,甚至更加安全. 一般来说,从接口宽度 ...
- bash shell(5):if,else,while大小比较
1.if :else 语句 .if的单分支语法格式: if 条件判断;then 语句1 语句2 …… else 语句1 语句2 …… fi .if的多分支语法格式: if 条件判断:then 语句1 ...
- [DIOCP3-IocpTask说明书]基于IOCP引擎的多线程任务的投递和回调处理单元
[说明] IocpTask是基于Iocp引擎的多线程任务投递和处理单元,可以方便的把任务进行投递到IOCP线程进行统一调度和处理,是模仿QDAC-QWorker的处理方式,支持D7以上的版本. [使用 ...
- HA&Federation【转】
转自:http://blog.csdn.net/tutucute0000/article/details/39756123 从nameNode1.namenode2克隆出namenode3.namen ...