collector

<?php set_time_limit(0); header("Content-type:text/html;charset=utf8"); /** * 採集程序類 * @author Administrator * */ class Collector { public $pages = array(); public $result = array();//結果 public $startUrls = array();//第一層連接 public $timeout = 80; public $httpContent; public $httpHead = array();//文件頭 public $putHead = array();//自定底的文件頭 public $fields = array();//採集的字段 public $deepth; //採集層次數 public $layout_arr;//層次結構 public $limit =0 ;//採集限制條數 public $runtime = 0;//程序運行時間 public $charset = 'UTF-8'; public $httpreferer; public $pagelimit = 0; public $filepath = './'; /** * 運行採集 * * @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] ['pattern'], $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] ['pattern'], $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 = '', $content = '') { if (strpos ( $pattern, '{*}' ) === false) return array ( $pattern ); $pattern = preg_quote ( $pattern ); $pattern = str_replace ( '\{\*\}', '([^\'\">]*)', $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 = '') { $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 . '(' . $errno . ')' ); $output = "GET $url HTTP/1.0\r\nHost: $host\r\n"; if (! isset ( $this->putHead ['Accept'] )) $this->putHead ['Accept'] = "*/*"; if (! isset ( $this->putHead ['User-Agent'] )) $this->putHead ['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)'; if (! isset ( $this->putHead ['Refer'] )) { $this->putHead ['Refer'] = ($referer == '') ? 'http://' . $host : $referer; } foreach ( $this->putHead as $headname => $headvalue ) { $output .= trim ( $headname ) . ': .trim($headvalue)."\r\n"'; } $output .= "Connection: close\r\n\r\n"; fwrite ( $fsp, $output ); $content = ''; while ( ! feof ( $fsp ) ) { $content .= fgets ( $fsp, 256 ); } fclose ( $fsp ); $this->getHead ( $content ); $this->httpContent = $content; if (strtoupper ( $this->charset ) != 'UTF-8') { $content = iconv ( $this->charset, 'utf-8', $content ); } else if (! empty ( $this->httpHead ['charset'] ) && $this->httpHead ['charset'] != 'UTF-8') { $content = iconv ( $this->httpHead ['charset'], 'utf-8', $content ); } $this->httpreferer = $referer; return $content; } /** * 按照規則從內容提取全部字段 * * @param Array * @return Array */ function filterContent($content = '') { $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, '#' ); 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] . '://'; $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['pattern'],'{'.$fieldinfo['field'].'}') === false) return $fieldinfo['pattern']; if($fieldinfo['isregular'] == 'true'){ $pattern = $fieldinfo['pattern']; $pattern = str_replace('{'.$fieldinfo['field'].'}','(?P<'.$fieldinfo['field'].'>.*?)',$pattern); }else{ $pattern = preg_quote($fieldinfo['pattern']); $pattern = str_replace('\{'.$fieldinfo['field'].'\}','(?P<'.$fieldinfo['field'].'>.*?)',$pattern); } $pattern = "~".$pattern."~is"; preg_match($pattern,$content,$preg_rs); $fieldresult = $preg_rs[$fieldinfo['field']]; /** * 去掉換行符 */ $fieldresult = preg_replace("~[\r\n]*~is",'',$fieldresult); /** * 對採集到的結果根據規則再進行二次替換處理 */ $replace_arr = $fieldinfo['replace']; 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['nextpage'] != ''){ $pattern = $fieldinfo['nextpage']; $pattern = str_replace('{nextpage}','(?P[^\'\">]*?)',$pattern); $pattern = "~".$pattern."~is"; if(preg_match($pattern,$content,$preg_rs) && $preg_rs['nextpage'] != ''){ $fieldresult .= $this->getPregField($fieldinfo,$this->getContent($preg_rs['nextpage'],$this->httpreferer)); } } } if(!empty($fieldinfo['callback']))$fieldresult = $fieldinfo['callback']($fieldresult); return $fieldresult; } /** * 添加一個採集字段和規則 * * @param string $field * @param string $pattern */ function addField($field,$pattern,$replace_arr='',$isregular='false',$nextpage = '',$callback='') { $rs = array( 'field' => $field, 'pattern' => $pattern, 'replace' => $replace_arr, 'isregular' => $isregular, 'nextpage' => $nextpage, 'callback'=>$callback ); $this->field_arr[$field] =$rs; } /** * 輸出 */ function output() { echo "The result is:<pre>"; echo "runtime :$this->runtime S"; print_r( $this->result ); echo "</pre>"; } /** * 輸出到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 = 'div') { $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 ); } } ?>php

相關文章
相關標籤/搜索