Maison  >  Article  >  php教程  >  采集 PHP

采集 PHP

PHP中文网
PHP中文网original
2016-05-25 17:15:101571parcourir

充分利用正则的强大字串处理能力,使用简单,功能也比较简单,能满足一般应用,功能也在不断完善中,使用过程:设置一个初始url,添加导航规则,添加采集字段和规则,保存输出即可

<?php
set_time_limit(0);
header("Content-type: text/html; charset=utf-8");
/**
* 采集程序类
* @author  shooting
* @version 1.0.0
*/
class spider
{
/**
* 采集的终端页地址
*
* @var array
*/
var $pages = array();
/**
* 采集结果
*
* @var array
*/
var $result = array();
/**
* 第一层链接页面
*
* @var array
*/
var $startUrls = array();
/**
* 超时时间
*
* @var integer
*/
var $timeout;
/**
* 正在处理的文件内容
*
* @var string
*/
var $httpContent;
/**
* 正在处理的文件头
*
* @var array
*/
var $httpHead=array();
/**
* 自定义的head数组
*
* @var array
*/
var $putHead = array();
/**
* 采集字段与规则数组
*
* @var array
*/
var $field_arr = array();
/**
* 采集层次数
*
* @var interger
*/
var $deep;
/**
* 采集层次结构
*
* @var array
*/
var $layout_arr = array();
/**
* 采集限制条数
*
* @var integer
*/
var $limit = 0;
/**
* 程序运行时间
*
* @var float
*/
var $runtime = 0;
/**
* 被采集页面编码
*
* @var string
*/
var $charset = &#39;UTF-8&#39;;
/**
* 页面引用地址
*
* @var string
*/
var $httpreferer;
var $pagelimit = 0;
var $filepath = &#39;./&#39;;
function spider()
{
  $this->timeout = 30;
}
/**
* 运行采集
*
* @return array
*/
function run()
{
  $begintime = $this->microtime_float();
  $cnt = 1;
  foreach ($this->startUrls as $starturl){
  /**
   * 解析出起始地址中的页码区间
   */
   if(preg_match("~\{(\d+),(\d+)\}~",$starturl,$pagenum)){
    $pagebegin = intval($pagenum[1]);
    $pageend = intval($pagenum[2]);
    for(;$pagebegin<=$pageend;$pagebegin++){
     $starturl = str_replace($pagenum[0],$pagebegin,$starturl);
     $urllists = $this->getLists($this->layout_arr[0][&#39;pattern&#39;],$this->getContent($starturl));
     foreach ($urllists as $url){
      if(($this->limit > 0 && $cnt <= $this->limit)||$this->limit == 0)
      {
       $this->filterContent($this->getContent($url,$starturl));
       $cnt++;
      }
     }
    }
   }else{
    $urllists = $this->getLists($this->layout_arr[0][&#39;pattern&#39;],$this->getContent($starturl));
    foreach ($urllists as $url){
     if(($this->limit > 0 && $cnt <= $this->limit)||$this->limit == 0)
     {
      $this->filterContent($this->getContent($url,$starturl));
      $cnt++;
     }
    }
   }
  }
  $this->runtime =  $this->microtime_float()-$begintime;
  return $this->result;
}
/**
* 从文字段中根据规则提取出url列表
*
* @param string $pattern
* @param string $content
* @return Array
*/
function getLists($pattern=&#39;&#39;,$content=&#39;&#39;)
{
  if(strpos($pattern,&#39;{*}&#39;) === false)return array($pattern);
  $pattern = preg_quote($pattern);
  $pattern = str_replace(&#39;\{\*\}&#39;,&#39;([^\&#39;\">]*)&#39;,$pattern);
  $pattern = "~".$pattern."~is";
  preg_match_all($pattern,$content,$preg_rs);
  return array_unique($preg_rs[0]);
}
/**
* 获取指定url的html内容包括头
*
* @param string $url
* @return string
*/
function getContent($url,$referer = &#39;&#39;)
{
  $url = $this->urlRtoA($url,$referer);
  preg_match("/(http:\/\/)([^:\/]*):?(\d*)(\/?.*)/i",$url,$preg_rs);
  $host = $preg_rs[2];
  $port = empty($preg_rs[3])?80:$preg_rs[3];
  $innerUrl = $preg_rs[4];
  $fsp = fsockopen($host,$port,$errno,$errstr,$this->timeout);
  if(!$fsp)$this->log($errstr.&#39;(&#39;.$errno.&#39;)&#39;);
  $output = "GET $url HTTP/1.0\r\nHost: $host\r\n";
  if(!isset($this->putHead[&#39;Accept&#39;]))$this->putHead[&#39;Accept&#39;]= "*/*";
  if(!isset($this->putHead[&#39;User-Agent&#39;]))$this->putHead[&#39;User-Agent&#39;]=&#39;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)&#39;;
  if(!isset($this->putHead[&#39;Refer&#39;])){
   $this->putHead[&#39;Refer&#39;] = ($referer == &#39;&#39;)?&#39;http://&#39;.$host:$referer;
  }
  foreach ($this->putHead as $headname => $headvalue){
   $output .= trim($headname).&#39;: &#39;.trim($headvalue)."\r\n";
  }
  $output .= "Connection: close\r\n\r\n";
  fwrite($fsp,$output);
  $content = &#39;&#39;;
  while (!feof($fsp)) {
        $content .= fgets($fsp,256);
    }
    fclose($fsp);
    $this->getHead($content);
    $this->httpContent = $content;
    if(strtoupper($this->charset) != &#39;UTF-8&#39;){
     $content = iconv($this->charset,&#39;utf-8&#39;,$content);
    }else if(!empty($this->httpHead[&#39;charset&#39;]) && $this->httpHead[&#39;charset&#39;]!=&#39;UTF-8&#39;)
    {
    $content = iconv($this->httpHead[&#39;charset&#39;],&#39;utf-8&#39;,$content);
    }
    $this->httpreferer = $referer;
  return $content;
}
/**
* 按照规则从内容提取所有字段
* @param Array
* @return Array
*/
function filterContent($content=&#39;&#39;)
{
  $rs = array();
  foreach ($this->field_arr as $field => $fieldinfo){
   $rs[$field] = $this->getPregField($fieldinfo,$content);
  }
  $this->result[] = $rs;
}
/**
* 相对路径转化为绝对路径
*
* @param string $relative
* @param string $referer
* @return string
*/
function urlRtoA($relative,$referer)
{
  /**
   * 去除#后面的部分
   */
  $pos = strpos($relative,&#39;#&#39;);
  if($pos >0)$relative = substr($relative,0,$pos);
  /**
   * 检测路径如果是绝对地址直接返回
   */
  if(preg_match("~^(http|ftp)://~i",$relative))
  return $relative;
  /**
   * 解析引用地址,获得协议,主机等信息
   */
  preg_match("~((http|ftp)://([^/]*)(.*/))([^/#]*)~i", $referer, $preg_rs);
  $parentdir = $preg_rs[1];
  $petrol = $preg_rs[2].&#39;://&#39;;
  $host = $preg_rs[3];
  /**
   * 如果以/开头的情况
   */
  if(preg_match("~^/~i",$relative))
   return $petrol.$host.$relative;
  return $parentdir.$relative;
}
/**
* 根据规则提取一个字段
*
* @param string $pattern
* @param string $content
* @return string
*/
function getPregField($fieldinfo,$content)
{
  /**
   * 规则为固定值的情况,直接返回固定值
   */
  if(strpos($fieldinfo[&#39;pattern&#39;],&#39;{&#39;.$fieldinfo[&#39;field&#39;].&#39;}&#39;) === false)
  return $fieldinfo[&#39;pattern&#39;];
  if($fieldinfo[&#39;isregular&#39;] == &#39;true&#39;){
   $pattern = $fieldinfo[&#39;pattern&#39;];
   $pattern = str_replace(&#39;{&#39;.$fieldinfo[&#39;field&#39;].&#39;}&#39;,&#39;(?P<&#39;.$fieldinfo[&#39;field&#39;].&#39;>.*?)&#39;,$pattern);
  }else{
   $pattern = preg_quote($fieldinfo[&#39;pattern&#39;]);
   $pattern = str_replace(&#39;\{&#39;.$fieldinfo[&#39;field&#39;].&#39;\}&#39;,&#39;(?P<&#39;.$fieldinfo[&#39;field&#39;].&#39;>.*?)&#39;,$pattern);
  }
  $pattern = "~".$pattern."~is";
  preg_match($pattern,$content,$preg_rs);
  $fieldresult = $preg_rs[$fieldinfo[&#39;field&#39;]];
  /**
   * 去掉换行符
   */
  $fieldresult = preg_replace("~[\r\n]*~is",&#39;&#39;,$fieldresult);
  /**
   * 对采集到的结果根据规则再进行二次替换处理
   */
  $replace_arr = $fieldinfo[&#39;replace&#39;];
  if(is_array($replace_arr)){
   $replace_arr[0] = "~".$replace_arr[0]."~s";
   $fieldresult = preg_replace($replace_arr[0],$replace_arr[1],$fieldresult);
  }
  /**
   * 针对有下一页的字段递归采集
   */
  if($this->pagelimit == 0){
  if($fieldinfo[&#39;nextpage&#39;] != &#39;&#39;){
   $pattern = $fieldinfo[&#39;nextpage&#39;];
   $pattern = str_replace(&#39;{nextpage}&#39;,&#39;(?P<nextpage>[^\&#39;\">]*?)&#39;,$pattern);
   $pattern = "~".$pattern."~is";
   if(preg_match($pattern,$content,$preg_rs) && $preg_rs[&#39;nextpage&#39;] != &#39;&#39;){
    $fieldresult .= $this->getPregField($fieldinfo,$this->getContent($preg_rs[&#39;nextpage&#39;],$this->httpreferer));
   }
  }
  }
  if(!empty($fieldinfo[&#39;callback&#39;]))$fieldresult = $fieldinfo[&#39;callback&#39;]($fieldresult);
  return $fieldresult;
}
/**
* 添加一个采集字段和规则
*
* @param string $field
* @param string $pattern
*/
function addField($field,$pattern,$replace_arr=&#39;&#39;,$isregular=&#39;false&#39;,$nextpage = &#39;&#39;,$callback=&#39;&#39;)
{
  $rs = array(
    &#39;field&#39; => $field,
    &#39;pattern&#39; => $pattern,
    &#39;replace&#39; => $replace_arr,
    &#39;isregular&#39; => $isregular,
    &#39;nextpage&#39; => $nextpage,
    &#39;callback&#39;=>$callback
    );
  $this->field_arr[$field] =$rs;
}
/**
* 输出
*
*/
function output()
{
  echo "The result is:<br/>";
  echo "runtime :$this->runtime S<br/><pre class="brush:php;toolbar:false">";
  print_r($this->result);
  echo "
"; } /** * 输出到XLS文件 * * @param string $file */ function saveXls($file = 'spider_result.xls') { $fp = fopen($file,'w'); if($fp){ foreach ($this->result as $result) { $line = implode("\t",$result)."\n"; fputs($fp,$line); } } fclose($fp); echo 'The result has been saved to '.$file.'.
Cost time:'.$this->runtime; } function saveSql($table = 'spider_result',$file = 'spider_result.sql') { $fp = fopen($file,'w'); if($fp){ foreach($this->field_arr as $fieldinfo){ $sql_key .= ', `'.$fieldinfo['field'].'`'; } $sql_key = substr($sql_key,1); foreach ($this->result as $result) { $sql_value = array(); foreach ($result as $key => $value){ $sql_value[] = "'".$this->addslash($value)."'"; } $line ="INSERT INTO `$table` ( $sql_key ) VALUES (".join(', ',$sql_value).");\r\n"; fputs($fp,$line); } } fclose($fp); echo 'The result has been saved to '.$file.'.
Cost time:'.$this->runtime; } /** * 取得响应内容的头部信息 * * @param string $content * @return array */ function getHead($content) { $head = explode("\r\n\r\n",$content); $head = $head[0]; // echo $head; if(!preg_match("~charset\=(.*)\r\n~i",$head,$preg_rs)) preg_match('~charset=([^\"\']*)~i',$content,$preg_rs); $this->httpHead['charset'] = strtoupper(trim($preg_rs[1])); // preg_match("~charset\=(.*)~i",$head,$preg_rs); return $this->httpHead; } /** * 设置采集页面的编码 * 在程序不能自动识别的情况下采集前要手动调用此函数 * * @param string $charset */ function setCharset($charset){ $this->charset = strtoupper($charset); } /** * 设置第一层链接页面地址 * * @param array $url_arr */ function setStartUrls($url_arr) { $this->startUrls = $url_arr; } /** * 增加一个第一层链接页面地址 * * @param string $url */ function addStartUrl($url) { $this->startUrls[] = $url; } /** * 添加一个采集层次 * * @param integer $deep * @param string $layout * @param boolean $isSimple * @param boolean $isPageBreak * @param string $pattern */ function addLayer($deep,$layout,$pattern = '',$isSimple = 'false',$isPageBreak = 'false') { $this->layout_arr[$deep] = array( 'layout'=>$layout, 'isSimple'=>$isSimple, 'isPageBreak'=>$isPageBreak, 'pattern'=>$pattern ); } /** * 自定义head * @param string $namespace * @param string $value */ function setHead($name,$value) { $this->putHead[$name] = $value; } /** * 清除html代码 * @param string $content; * @param string $cleartags * @return string */ function clearHtml($content,$cleartags = 'p') { $cleartags_arr = explode('|',$cleartags); foreach ($cleartags_arr as $cleartag){ $pattern = '~<\/?'.$cleartag.'[^>]*>~is'; $content = preg_replace($pattern,'',$content); } return $content; } /** * 日志 * */ function log($str) { echo $str."
\n"; } /** * 获取采集运行时间 * * @return float */ function getRuntime() { return $this->runtime; } function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } function addslash($string) { return addslashes($string); } } $spider = new spider(); $spider->addStartUrl('http://hi.baidu.com/shuntian/blog/index/{0,5}'); $spider->setCharset('gb2312'); $spider->addLayer(0,'list','/shuntian/blog/item/{*}.html'); $spider->addField('title','{title}',array('_顺者的天空-shooting's sky ','')); $spider->addField('body','

{body}

'); $spider->addField('author','shooting'); $spider->run(); $spider->saveSql();

 以上就是采集的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn