本文作者:心月

curl_multi实现多线程采集处理

心月IT博客 2019-10-26
curl_multi实现多线程采集处理摘要: curl​普通的单线程请求是通过 curl_init 实例化然后通过 curl_exec 执行并获取我们想要的信息,如果是多线程的话,则需用通过 curl_multi 系列函数来实现。

        我们都知道curl可以发送模拟浏览器请求来获取指定页面源码,很多PHPer会利用curl扩展的这个特性来采集数据。但采集往往都是针对大量页面处理的,如果使用循环一个一个页面的处理会非常耗时,但如果能同时对多个页面进行采集,将可以缩短很多时间。

        curl普通的单线程请求是通过 curl_init 实例化然后通过 curl_exec 执行并获取我们想要的信息,如果是多线程的话,则需用通过 curl_multi 系列函数来实现。

下面我们同实例来实现 curl 的多线程请求

以抓取百度搜索结果为例:

        关键词 “搜索优化”

        url数量:搜索结果前50页

        数据采集目标:每个自然搜索结果的标题


1、curl 单线程数据采集处理

<?php

	$start = time();
	$header = [
            'Content-Type: text/html;charset=utf-8',
            'Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Accept-Language: zh-CN,zh;q=0.9',
            'Cache-Control: no-cache',
            'Connection: keep-alive',
            'Host:www.baidu.com',
            'Pragma: no-cache',
            'Upgrade-Insecure-Requests:1',
            'Referer:https://www.baidu.com/',
            'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3239.132 Safari/537.36',
            'X-Requested-With:XMLHttpRequest'
        ];

    $contents = [];

	for ($i=0; $i < 50 ; $i++) {
		
		if ($i > 0) {
			$num = 10*$i;
			$url = "https://www.baidu.com/s?wd=搜索优化&pn=".$num;
		}else{
			$url = "https://www.baidu.com/s?wd=搜索优化";
		}

		$ch = curl_init();
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_HTTPHEADER, $header );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        $contents[] = curl_exec ( $ch );

        curl_close ( $ch );
	}

	
	foreach ($contents as $content) {
		$titleRes[] = getTitle($content);
	}


	var_dump($titleRes);

	$end = time();

	echo "<hr>";
	echo "程序执行耗时:".($end-$start).'秒';
        
        //搜索结果标题提取
	function getTitle($content){
        preg_match_all('/<h3([^<>]*)>(.*)<\/h3>/Uis',$content,$arr);

        $title = [];
        if (!empty($arr[2])){
        	foreach ($arr[2] as $value) {
        		$title[] = strip_tags($value);
        	}
            
        }

    	return $title;
    }

程序运行情况

curl单线程数据采集处理


2、curl 多线程数据采集处理

<?php

	$start = time();
	//设置百度搜索请求头
	$header = [
            'Content-Type: text/html;charset=utf-8',
            'Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Accept-Language: zh-CN,zh;q=0.9',
            'Cache-Control: no-cache',
            'Connection: keep-alive',
            'Host:www.baidu.com',
            'Pragma: no-cache',
            'Upgrade-Insecure-Requests:1',
            'Referer:https://www.baidu.com/',
            'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3239.132 Safari/537.36',
            'X-Requested-With:XMLHttpRequest'
        ];

	$chs = [];

	for ($i=0; $i < 50 ; $i++) {
		
		if ($i > 0) {
			$num = 10*$i;
			$url = "https://www.baidu.com/s?wd=搜索优化&pn=".$num;
		}else{
			$url = "https://www.baidu.com/s?wd=搜索优化";
		}

		$chs[$i] = curl_init();
        curl_setopt ( $chs[$i], CURLOPT_URL, $url );
        curl_setopt ( $chs[$i], CURLOPT_HTTPHEADER, $header );
        curl_setopt ( $chs[$i], CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $chs[$i], CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt( $chs[$i], CURLOPT_SSL_VERIFYHOST, FALSE);

	}
        
        //多线程处理的关键
        
	$mh = curl_multi_init();//创建批处理cURL句柄

	foreach ($chs as $ch) {
		curl_multi_add_handle($mh, $ch); // 将单个curl 句柄加入批处理 curl句柄中
	}

	$running=null;
	// 执行批处理句柄
	do {
	    usleep(10000);
	    curl_multi_exec($mh,$running); //执行批处理句柄
	} while ($running > 0);

	$contents = [];
	foreach($chs as $k => $ch){ 
	    $contents[] = curl_multi_getcontent($ch); // 获取句柄的返回值
	    curl_multi_remove_handle($mh, $ch);// 将$mh中的句柄移除
	}

	curl_multi_close($mh); //关闭全部句柄

	$titleRes = [];
	foreach ($contents as $content) {
		$titleRes[] = getTitle($content);
	}


	var_dump($titleRes);

	$end = time();

	echo "<hr>";
	echo "程序执行耗时:".($end-$start).'秒';
        
        //搜索结果标题提取
	function getTitle($content){
        preg_match_all('/<h3([^<>]*)>(.*)<\/h3>/Uis',$content,$arr);

        $title = [];
        if (!empty($arr[2])){
        	foreach ($arr[2] as $value) {
        		$title[] = strip_tags($value);
        	}
            
        }

    	return $title;
    }

程序运行情况

curl单线程数据采集处理

        单线程处理50个页面耗时17s,使用 curl_multi 后同样的50个页面耗时6s,缩短了65%左右的时间,数据采集效率大大提升了。不过50个页面curl多线程也耗时6s,这个效率算不得有多高,curl_multi 还是有很大的优化空间的。

文章版权及转载声明:

本文由 心月IT技术博客 博主整理于 2019-10-26
若转载请注明原文及出处:https://www.xinyueseo.com/other/437.html

分享到:
赞(
发表评论
快捷输入:

验证码

    评论列表 (有 0 条评论,人围观)参与讨论