如何在PHP cURL multi执行过程中实时处理返回结果?
在PHP cURL Multi循环中实时处理请求结果
完全可以在下载循环中实时处理返回结果,这确实能更早释放cURL句柄、减少资源占用,还能让爬虫的并发效率更稳定——不用等所有请求都结束再批量处理。
你提到的curl_multi_select确实不会直接返回哪个请求完成,但可以配合curl_multi_info_read()来获取所有已完成的请求状态,从而实现实时处理。下面是修改后的核心代码,替换你原来的下载循环和结果收集部分:
<?php $remainingTargets = ...; $concurrency = 30; $multiHandle = curl_multi_init(); $targets = []; // 初始化第一批请求 while (count($targets) < $concurrency && count($remainingTargets) > 0) { $target = array_shift($remainingTargets); $alreadyChecked = ...; if ($alreadyChecked !== false) { continue; } $curl = curl_init($target); curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36'); curl_setopt($curl, CURLOPT_FAILONERROR, true); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 4); curl_setopt($curl, CURLOPT_TIMEOUT, 5); curl_multi_add_handle($multiHandle, $curl); // 新增:用句柄作为键,方便反向查找目标 $targets[(int)$curl] = $target; } // 改进后的下载循环:实时处理完成的请求 $running = null; do { // 等待活动连接,避免空循环占用CPU curl_multi_select($multiHandle); // 执行当前的cURL批处理 curl_multi_exec($multiHandle, $running); // 循环读取所有已完成的请求信息 while ($info = curl_multi_info_read($multiHandle)) { $curl = $info['handle']; $target = $targets[(int)$curl]; if ($info['result'] === CURLE_OK) { // 成功获取内容,实时处理 $html = curl_multi_getcontent($curl); // 这里直接处理页面:解析链接、存储数据等 // Process this page } else { // 处理请求失败的情况,比如记录错误日志 $error = curl_error($curl); // Handle error } // 立即释放资源 curl_multi_remove_handle($multiHandle, $curl); curl_close($curl); unset($targets[(int)$curl]); // 补充新的请求,维持并发数 if (count($remainingTargets) > 0) { $newTarget = array_shift($remainingTargets); $alreadyChecked = ...; if ($alreadyChecked === false) { $newCurl = curl_init($newTarget); // 复用之前的curl配置 curl_setopt($newCurl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36'); curl_setopt($newCurl, CURLOPT_FAILONERROR, true); curl_setopt($newCurl, CURLOPT_RETURNTRANSFER, true); curl_setopt($newCurl, CURLOPT_CONNECTTIMEOUT, 4); curl_setopt($newCurl, CURLOPT_TIMEOUT, 5); curl_multi_add_handle($multiHandle, $newCurl); $targets[(int)$newCurl] = $newTarget; } } } } while ($running > 0 || count($targets) > 0); curl_multi_close($multiHandle);
关键改进点:
- 用句柄作为$targets数组的键:方便根据返回的句柄快速找到对应的请求目标,避免遍历查找
- curl_multi_select:等待cURL批处理中有活动状态变化,避免无意义的空循环,降低CPU占用
- curl_multi_info_read:循环取出所有已完成的请求,不管是成功还是失败,都能实时处理
- 即时释放资源:处理完一个请求就立即移除句柄并关闭,不用等到所有请求结束
- 维持并发数:每释放一个句柄,就从剩余目标中补充新的请求,保持设定的并发量(30)
这样修改后,爬虫的资源利用率会更高,尤其是在处理大量请求时,能更快释放内存和连接资源,避免长时间占用过多句柄。
内容的提问来源于stack exchange,提问作者William Entriken
相关产品推荐
相关产品推荐

