PHP多进程抓取百度搜索结果

原创 2016年08月29日 11:05:34
<?php
/**
 *  多进程抓取百度结果页自然结果,包括标题、摘要、图片、链接、来源
 *  @since 2016-04-15
 */
class NaturalResultSpider {

	private $_strQuery = null;

	public $worker_process = 4;      //开启进程数

	private $_arrPids = array();

	private $_intPageNum;         //需要抓取的自然结果页数

	public $arrAllResult = array();

	public $dataHandler = null;    //钩子,可以回调指定的函数完成对应功能

	private $masterPid = null;

	private $retry_times = 1;

	private $strReg = '/<div\sclass="result\sc-result\sc-clk-recommend"(.*)?>(.*)?(<img\ssrc="(.*)?">)?(.*)?(<p\sclass="c-line-clamp3\sc-color">(.*)?)+<\/div>/Uis';

	private static $_arrPattern = array(
		array('name'=>'nature_result', 'reg'=>'/data-log=\"(.*?)\"/', 'location'=>1),
		array('name'=>'title', 'reg'=>'/<h3(.*?)>(.*?)<\/h3>/', 'location'=>2),
		array('name'=>'abstract', 'reg'=>'/<p class=\"c-line-clamp3 c-color\">(.*?)<\/p>/', 'location'=>1),
		array('name'=>'source_url', 'reg'=>'/<div class=\"c-showurl c-line-clamp1\"><span>(.*?)<\/span>/', 'location'=>1),
		array('name'=>'url', 'reg'=>'/<div class=\"c-container\"><a(.*?)class=\"c-blocka\" href=\"(.*?)\">/', 'location'=>2),
		array('name'=>'img', 'reg'=>'/<div class=\"c-img c-img-s\"><img data-imagedelaysrc=\"(.*?)\"/', 'location'=>1),
	);

	public function __construct($strQuery, $intPageNum=76) {
		$this->_strQuery = $strQuery;
		$this->_intPageNum = $intPageNum;
	}

	public function execute() {
		$this->setMasterPid();
		$this->forkWorker();
		$this->monitorWorker();
	}

	private function setMasterPid() {
		$this->masterPid = posix_getpid();
	}

	public function setWorkerProcess($intWorkerProcess) {
		if ($intWorkerProcess <= 0) {
			return false;
		}
		$this->worker_process = $intWorkerProcess;
	}

	public function setRetryTimes($intTimes) {
		if ($intTimes <= 0) {
			return false;
		}
		$this->retry_times = $intTimes;
	}

	public function setRegPattern($strReg) {
		if (empty($strReg)) {
			return false;
		}
		$this->strReg = $strReg;
	}

	public function setPattern($arrPattern) {
		if (!is_array($arrPattern) || empty($arrPattern)) {
			return false;
		}
		self::$_arrPattern[] = $arrPattern;
	}

	private function monitorWorker() {
		if ($this->masterPid === posix_getpid()) {
			foreach ($this->_arrPids as $intPid) {
				pcntl_waitpid($intPid, $status, WUNTRACED);
				$status = pcntl_wexitstatus($status);
				if ($status === 100) {
					unset($this->_arrPids[$inPid]);
				}
			}
		}
	}

	/*主调用方法*/
	public function forkWorker() {

		for ($i=0; $i<$this->worker_process; ++$i) {

			$pid = pcntl_fork();

			if ($pid === -1) {
				exit;
			} elseif ($pid > 0) {
				$this->_arrPids[$pid] = $pid;
			} else {
				$arrResult = $this->run($i);
				if ($this->dataHandler) {
					call_user_func($this->dataHandler, $arrResult);
				}
				exit(100);
			}
		}
	}

	/*为worker分配任务*/
	private function run($intWorkerId) {

		$intPage = ceil($this->_intPageNum / $this->worker_process);

		$intBegin = $intWorkerId * $intPage;

		$intEnd = ($intWorkerId + 1) * $intPage;

		$intEnd = $intEnd > $this->_intPageNum ? $this->_intPageNum : $intEnd;

		for ($i=$intBegin; $i<$intEnd; ++$i) {

			$strUrl = 'm.baidu.com/s?word=' . urlencode($this->_strQuery);
			$strUrl .= $i == 0 ? '' : '&pn=' . $i*10;
			//如果失败则重试
			$error_times = 0;
			while (true) {
				if ($error_times >= $this->retry_times) {
					break;
				}
				$strHtml = $this->curl($strUrl);
				$arrMatches = $this->getHtmlContent($strHtml);
				$arrNaturalResult = $this->getNaturalResult($arrMatches);
				if (!empty($arrNaturalResult)) {
					$arrResult[$i] = $arrNaturalResult;
					break;
				}
				$error_times++;
			}
		}
		return $arrResult;
	}

	private function curl($url) {

		$ch = curl_init();

		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 10);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);

		$result = curl_exec($ch);

		if (curl_errno($ch)) {
			exit;
		}

		return $result;
	}

	public function getHtmlContent($strHtml) {

		if (empty($strHtml)) {
			return false;
		}

		preg_match_all($this->strReg, $strHtml, $arrMatches);

		return $arrMatches[0];
	}

	public function getNaturalResult($arrMatches) {

		if (empty($arrMatches) || !is_array($arrMatches)) {
			return false;
		}

		$arrNaturalResult = array();

		foreach ($arrMatches as $key=>$div) {

			foreach (self::$_arrPattern as $val) {
				$strName = $val['name'];
				$$strName = '';
			}

			foreach (self::$_arrPattern as $val) {

				$strName = $val['name'];

				preg_match_all($val['reg'], $div, $matches);

				if (!isset($matches[$val['location']][0])) {
					continue;
				}

				$$strName = isset($matches[$val['location']][0]) ? $matches[$val['location']][0] : '';

				if ($val['name'] === 'nature_result') {

					$$strName = str_replace('\'', '"', $$strName);
					$$strName = json_decode($$strName, true);
				} else {
					$$strName = strip_tags($$strName);
				}
				$arrNaturalResult[$key][$val['name']] = $$strName;
			}
		}

		return $arrNaturalResult;
	}
}

调用方法:

$obj = new NaturalResultSpider($strQuery, $pageNo);

指定需要抓取什么query的搜索结果,和抓取的页数,最多76页

$obj->setWorkerProcess(4);

指定4个进程进行抓取

$obj->setRetryTimes(3);

抓取失败重试次数

$obj->dataHandler = 'printRes';

指定回调方法进行数据处理

$obj->execute();

以上设置好之后开始运行

相关文章推荐

PHP抓取百度搜索结果对应的第一个百度快照的链接

利用正则,代码如下: public function kuaizhaoo() { $text = '你要搜索的内容'; $url = 'http://www.baidu.com/...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

PHP抓取百度搜索结果页面的【相关搜索词】并存储

一、百度搜索关键词【知了壳公司转让】【知了壳公司转让】搜索链接 https://www.baidu.com/s?wd=%E7%9F%A5%E4%BA%86%E5%A3%B3%E5%85%AC%E5%...
  • vailook
  • vailook
  • 2016年11月15日 13:37
  • 1781

PHP扩展pcntl(进程控制以及信号处理)中文文档

转自 PHP扩展pcntl(进程控制以及信号处理)中文文档 PHP 扩展 pcntl 实现 ” 多线程 ”( 进程 ) pcntl 与 ticks ticks 是...

用gdb调试多进程和多线程的服务器程序

转自:http://bbs.chinaunix.net/viewthread.php?tid=1609486&page=3&authorid=207013291楼发表于 2009-11-06 15:1...

php 抓取百度搜索结果脚本

  • 2015年03月05日 21:21
  • 2KB
  • 下载

使用HtmlUnit抓取百度搜索结果

htmlunit 是一款开源的java 页面分析工具,读取页面后,可以有效的使用htmlunit分析页面上的内容。项目可以模拟浏览器运行,被誉为java浏览器的开源实现。这个没有界面的浏览器,运行速度...

分别使用Python和Java抓取百度搜索结果

最近有了点空闲学习了下Python的语法,还别说,Java学习了一段时间之后看Python的语法简单多了。记得当时主要用C语言开发的时候,看Python的代码有点困难。     看了下Pyt...
  • zjutzmh
  • zjutzmh
  • 2016年11月17日 21:32
  • 515
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:PHP多进程抓取百度搜索结果
举报原因:
原因补充:

(最多只允许输入30个字)