我自仰头向天笑,笑完我就去睡觉,哈哈哈哈……

用PHP的curl实现并发请求远程文件(并发抓取远程网页)

 

PHP的curl功能确实强大了。里面有个curl_multi_init功能,就是批量处理任务。可以利用此,实现多进程同步抓取多条记录,优化普通的网页抓取程序。

一个简单的抓取函数:

复制代码
function http_get_multi($urls){
    $count = count($urls);
    $data = [];
    $chs = [];

    // 创建批处理cURL句柄
    $mh = curl_multi_init();

    // 创建cURL资源
    for($i = 0; $i < $count; $i ++){
        $chs[ $i ] = curl_init();
        // 设置URL和相应的选项
        curl_setopt($chs[ $i ], CURLOPT_RETURNTRANSFER, 1); // return don't print
        curl_setopt($chs[ $i ], CURLOPT_URL, $urls[$i]);
        curl_setopt($chs[ $i ], CURLOPT_HEADER, 0);

        curl_multi_add_handle($mh, $chs[ $i ]);
    }
    // 增加句柄
    // for($i = 0; $i < $count; $i ++){
        // curl_multi_add_handle($mh, $chs[ $i ]);
    // }

    // 执行批处理句柄
    do {
        $mrc = curl_multi_exec($mh, $active);
    } while ($active > 0);

    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);
        }
    }

    for($i = 0; $i < $count; $i ++){
        $content  = curl_multi_getcontent($chs[ $i ]);
        $data[ $i ] = ( curl_errno($chs[ $i ]) == 0 ) ? $content : false;
    }
    // 关闭全部句柄
    for($i = 0; $i < $count; $i ++){
        curl_multi_remove_handle($mh, $chs[ $i ]);
    }
    curl_multi_close($mh);
    return $data;
}
复制代码

 

下面的调用测试(get()函数如这里: http://www.cnblogs.com/whatmiss/p/7114954.html):

复制代码
//弄很多个网页的url
$url
= [ 'http://www.baidu.com', 'http://www.163.com', 'http://www.sina.com.cn', 'http://www.qq.com', 'http://www.sohu.com', 'http://www.douban.com', 'http://www.cnblogs.com', 'http://www.taobao.com', 'http://www.php.net', ]; $urls = []; for($i = 0; $i < 10; $i ++){ foreach($url as $r) $urls[] = $r . '/?v=' . rand(); }

//并发请求
$datas = http_get_multi($urls); foreach($datas as $key => $data){ file_put_contents('log/multi_' . $key . '.txt', $data); // 记录一下请求结果。记得创建一个log文件夹 } $t2 = microtime(true); echo $t2 - $t1; echo '<br />';

//同步请求, get()函数如这里: http://www.cnblogs.com/whatmiss/p/7114954.html
$t1 = microtime(true); foreach($urls as $key => $url){ file_put_contents('log/get_' . $key . '.txt', get($url)); // 记录一下请求结果。记得创建一个log文件夹 } $t2 = microtime(true); echo $t2 - $t1;
复制代码

 

测试结果,很明显的差距,而且随着数据量越大,会呈指数级的拉大差距:

复制代码
2.4481401443481
21.68923997879

8.925509929657
24.73141503334

3.243185043335
23.384337902069

3.2841880321503
24.754415035248
 
3.2091829776764
29.068662881851
复制代码

 

参考,感谢原作者:

http://php.net/manual/zh/function.curl-multi-init.php

http://www.tuicool.com/articles/auiEBb

http://blog.csdn.net/liylboy/article/details/39669963 此文写了可能超时的问题

 

另,这里有一篇文章说,多线程并不会更快,甚至还稍慢一点点,我觉得很奇怪,怎么会有这样的结果:

http://www.webkaka.com/tutorial/php/2013/102843/

posted @   轻轻的烟雾  阅读(1675)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示