php exec 通过网页,php curl_multi_exec()并发抓取网页内容

php curl_multi_exec()并发抓取网页内容

php是个单线程的语言,于是在某方面速率比不上java这种多线程的语言,毕竟主打方面不在这里..但是php也有自己的多线程(其实是并发)方法--curl_multi_exec().

我们可以用curll来获取网页的内容(不懂curl的可以找个简单的例子来看看),但是若是同时获取多个网页的内容,速度就不太理想,这个时候curl_multi_exec()就可以发挥作用了。

下面是我在抓取优酷网内容的例子:

function async_get_url($url_array, $wait_usec = 0)

{

if (!is_array($url_array))

return false;

$wait_usec = intval($wait_usec);

$data = array();

$handle = array();

$running = 0;

$mh = curl_multi_init(); // multi curl handler

$i = 0;

foreach($url_array as $url) {

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return don't print

curl_setopt($ch, CURLOPT_TIMEOUT, 30);

curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 302 redirect

curl_setopt($ch, CURLOPT_MAXREDIRS, 7);

curl_multi_add_handle($mh, $ch); // 把 curl resource 放進 multi curl handler 裡

$handle[$i++] = $ch;

}

/* 此做法就可以避免掉 CPU loading 100% 的問題 */

// 參考自: http://www.hengss.com/xueyuan/sort0362/php/info-36963.html

do {

$mrc = curl_multi_exec($mh, $active);

} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active and $mrc == CURLM_OK) {

if (curl_multi_select($mh) != -1) {

do {

$mrc = curl_multi_exec($mh, $active);

} while ($mrc == CURLM_CALL_MULTI_PERFORM);

}

}

/*

// 感謝 Ren 指點的作法. (需要在測試一下)

// curl_multi_exec的返回值是用來返回多線程處裡時的錯誤,正常來說返回值是0,也就是說只用$mrc捕捉返回值當成判斷式的迴圈只會運行一次,而真的發生錯誤時,有拿$mrc判斷的都會變死迴圈。

// 而curl_multi_select的功能是curl發送請求後,在有回應前會一直處於等待狀態,所以不需要把它導入空迴圈,它就像是會自己做判斷&自己決定等待時間的sleep()。

/* 讀取資料 */

foreach($handle as $i => $ch) {

$content = curl_multi_getcontent($ch);

$data[$i] = (curl_errno($ch) == 0) ? $content : false;

}

/* 移除 handle*/

foreach($handle as $ch) {

curl_multi_remove_handle($mh, $ch);

}

curl_multi_close($mh);

return $data;

}

$url="http://m.youku.com/wap/";

$reg1="/(.*?)/i";//获取视频链接

$reg2="/

php-weizijiaocheng-233078.html]*)\s*class=\"imgdetail\"\s*src=('|\")([^'\"]+)('|\")/i";

$reg3="";

$reg4= "/

.*?/i";//获取视频标题(备选)

// 创建两个cURL资源

$ch1 = curl_init();

$resultArray=array();//装载所有数据的数组

$ch=array();

//$ch2 = curl_init();

// 指定URL和适当的参数

curl_setopt($ch1, CURLOPT_URL,$url);

curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch1, CURLOPT_HEADER, 0);

$content=curl_exec($ch1);

curl_close($ch1);

//$content=file_get_contents($url);

preg_match_all($reg1, $content,$matches);

$video=$matches[0];//首页视频的链接

//print_r($video);

foreach ($video as $a=>$key)

{

$position=strpos($key, "href");

$substring=substr($key, $position+11);

$pos=strpos($substring, ">");

$link=substr($substring, 0,$pos-1);

$nextUrl[$a]=$url.$link;

}

//$url_array = array(

// 'http://www.google.com',

// 'http://www.baidu.com',

//);

//print_r($nextUrl);

//print_r(async_get_url($nextUrl));

//并发获取所有网页的内容

$allData=async_get_url($nextUrl);

foreach ($allData as $page)

{

//获取视频图片

preg_match_all($reg2, $page,$img);

$img_arr=$img[0];

foreach ($img_arr as $arr)

{

$position=strpos($arr, "src");

$sub=substr($arr, $position+5);

$pos=strpos($sub, "\"");

$last=substr($sub, 0,$pos);

}

//获取视频高清点播地址

preg_match_all($reg3, $page,$vids);

$video_arr=$vids[0];

$vid=$video_arr[0];

$position=strpos($vid, "href");

$v_string=substr($vid, $position+11);

$pos=strpos($v_string, "\"");

$add=substr($v_string, 0,$pos);

$video_url=$url.$add;

//获取视频的标题

preg_match_all($reg4, $page,$match);

$title=$match[0];

//print_r($er);

$r=serialize($title);

$position=mb_strpos($r, "");

$sub=substr($r, 0,$position);

$pos=mb_strrpos($sub, ">");

$til=substr($sub, $pos+1);

//整合到一个数组

$subArray=array('image'=>$last,'video'=>$video_url,'title'=>$til);

array_push($resultArray, $subArray);

}

echo json_encode($resultArray);

重点在与async_get_url这个函数

do {

$mrc = curl_multi_exec($mh, $active);

} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active and $mrc == CURLM_OK) {

if (curl_multi_select($mh) != -1) {

do {

$mrc = curl_multi_exec($mh, $active);

} while ($mrc == CURLM_CALL_MULTI_PERFORM);

}

}

上面那段是重点也是难点。

第一个循环,$mrc == CURLM_CALL_MULTI_PERFORM(-1)表明了还有句柄资源没有处 理,于是就继续$mrc = curl_multi_exec($mh, $active)

要特别说明的是$mrc和$active都是integer类型的;

当$mrc== CURLM_OK(0),就表明了还有资源,但还没有到达。

这是就到第二个循环了:

(while)要是有资源还没有到达

(if)如果cURL批处理连接中有活动连接--也就是说句柄有事干了(具体可以参考php手册)

(do-while)处理句柄资源

curl并发处理因为官方文档比较简练,我自己也查了好多英文文档才略懂。

希望大家能一起进步!

参考文档:

http://technosophos.com/content/php-and-curlmultiexec

http://blog.longwin.com.tw/2009/10/php-multi-thread-curl-2009/

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
curlcurl_multi都是用于进行网络请求的工具。 curl是一个命令行工具,可以通过发送HTTP请求来获取网页内容或发送其他类型的网络请求。它是单线程的,在发送一个请求时会阻塞程序的执行直到请求完成并返回结果。这意味着如果要进行高并发的请求,需要启动多个curl进程来同时发送多个请求,但会造成系统资源的浪费。 而curl_multi是一个C语言库,可以实现多个网络请求的并发执行。它通过将多个curl实例放入一个集合中,并使用事件循环来处理多个请求的同时执行。这样,在发送一个请求时,程序不会阻塞,而是可以继续执行其他任务,提高了并发处理能力。当所有的请求都完成时,可以一次性获取所有的结果。这种方式减少了系统资源的浪费,提高了程序的效率。 使用curl_multi进行高并发需要注意以下几点: 1. 创建curl_multi实例,并向其中添加需要执行的curl请求。 2. 使用curl_multi_exec函数来开始执行多个请求。 3. 使用curl_multi_select函数等待请求完成。 4. 使用curl_multi_getcontent函数获取每个请求的结果。 需要注意的是,高并发的网络请求对服务器压力较大,也容易出现网络超时等问题,因此需要合理控制并发请求数量,使用适当的技术手段,如连接池、负载均衡等,来保证系统的稳定性和性能。 总之,curlcurl_multi都可以用于高并发的网络请求,但curl_multi具有更好的并发性能和资源利用率,适合在程序中进行大量请求的同时执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值