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

php中文网
发布: 2016-06-20 13:02:04
原创
1746人浏览过

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="/<a\s*href=\"(.*?)version=2\"(.*?)>(.*?)<\/a>/i";//获取视频链接
$reg2="/@@##@@]*)\s*class=\"imgdetail\"\s*src=('|\")([^'\"]+)('|\")/i";
$reg3="<a\s*href=\"(.*?)&format=3gphd\"\s*id=\"click_play\"\s*>";
$reg4= "/<p\s*class=\"videotitle\".*?>.*?<\/p>/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, "</p>");
    $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这个函数

立即学习PHP免费学习笔记(深入)”;

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),就表明了还有资源,但还没有到达。

这是就到第二个循环了:

启科网络PHP商城系统
启科网络PHP商城系统

启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。

启科网络PHP商城系统 0
查看详情 启科网络PHP商城系统

(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  curl_multi_exec()并发抓取网页内容

相关标签:
PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号