一個簡單的開源PHP爬蟲框架『Phpfetcher』

這篇文章首發在吹水小鎮:http://blog.reetsee.com/archives/366php

要在手機或者電腦看到更好的圖片或代碼歡迎到博文原地址。也歡迎到博文原地址批評指正。html

轉載請註明: 吹水小鎮 | reetsee.com
原文連接地址: http://blog.reetsee.com/archives/366
git

——————————————————————————————github


很久不見了!

我最終又寫一篇日誌了,原本有很是多流水賬想發但是感受沒養分,就做罷了。今天我主要分享一個簡單的PHP爬蟲框架。名字叫:Phpfetcher項目的地址是:https://github.com/fanfank/phpfetcher這個框架的做者是:reetsee.xu。即吹水。數據庫

把整個項目下載下來後,在Linux下的終端直接運行demo目錄下的single_page.php就能夠看到效果。bash

只是在運行demo文件前,先設置一下你的終端編碼爲UTF-8以避免顯示亂碼: 框架

export LANG=en_US.UTF-8
————————————————————————————————

0 背景

背景是這種眼下 吹水新聞http://news.reetsee.com)下的內容全部由Python的爬蟲抓取。使用的框架是Python的 Scrapy。而吹水新聞眼下是執行在 BAE(百度應用引擎)下的,每個月還需要交錢。眼下個人想法是把吹水新聞全然遷移到眼下這臺阿里雲主機上。而且本來的新聞我天天都手動執行一次腳原本抓取再更新到站點,等遷移到這裏後就能直接使用Crontab定時腳本本身主動更新新聞了!

近期工做都在用PHP,開發站點的新頁面要PHP,直接讀寫數據庫也能用PHP,那麼就直接用PHP重構新聞站點好了。dom

準備開乾的時候卻發現沒找到一個好的PHP爬蟲框架(多是我沒細緻找)。因而就打算本身寫一個,所以就有了這個Phpfetcher。名字起得略好……但是代碼寫得略搓……不管怎麼樣。眼下基本可以用,而且應該能知足很多簡單的需求,如下就是使用演示樣例。curl

 1 基本概念

在Phpfetcher中有四個基本的對象。依次是:Dom,Page。Crawler,Manager。
  • Dom對象用來解析html,能夠訪問html裏的dom
  • Page對象相應到一個詳細的html頁面,能夠取得整個網頁的內容,Page對象中有一個Dom對象的成員;
  • Crawler對象能夠理解爲就是爬蟲對象,用來設置要爬取頁面的規則。
  • Manager對象本來是用來管理Crawler對象的。之後也許能用來在多進程環境下使用,但眼下沒有實現,因此臨時沒實用;
大體概念就是這樣了,實際使用主要是操做Crawler對象。在Phpfetcher中。你可以實現本身的Dom,Page和Crawler,僅僅要符合基類的要求就能夠。

要說明的是Phpfetcher的默認Page對象中的Dom對象使用的是simple_html_dom,沒有使用PHP提供的DOMDocument類,因爲我發現DOMDocument對HTML格式的內容兼容性比較差。有時網頁中混入其餘內容時可能解析不出dom。如下這張是圖是Phpfetcher的文件夾結構:phpfetcher_文件夾結構你可以依據本身的需要定製想要的Crawler,Page,Dom類。默認狀況下我提供了Crawler的默認類是Phpfetcher_Crawler_Default。Page的默認類是Phpfetcher_Page_Default。Dom的默認類是Phpfetcher_Dom_SimpleHtmlDom。類名和它們所在的路徑有相應關係。要注意的是,在使用默認的Page對象時需要PHP的curl庫,使用默認的Crawler對象時需要使用PHP的mb_string庫,沒有的需要裝一下。爲了便於理解。我畫了幾張圖,第一張是Phpfetcher的三個主要對象之間的關係:phpfetcher_類結構圖裏表示的是Crawler裏面有Page的對象,Page裏面有Dom的對象。scrapy

在使用Phpfetcher時,最重要的是完畢下圖中兩個綠色矩形框要求的事情:phpfetcher_用戶使用即你要寫一個類繼承Phpfetcher提供的Crawler類,而後在你本身的類中實現一個名爲handlePage($page)的函數。

當中$page參數是一個Phpfetcher的Page類對象。最後這裏給出一個主要的流程圖:phpfetcher_工做流程圖 上面說的東西有點虛,那仍是直接看實例吧!

 

2 簡單樣例

****** 實例1:single_page.php ******好比咱們要抓取這個站點的內容: http://news.qq.com/a/20140927/026557.htm裏面有很是多超連接。有標題,有新聞具體內容。或者其餘咱們關心的內容。

先看一下如下的樣例:

<?

php require_once('phpfetcher.php'); class mycrawler extends Phpfetcher_Crawler_Default { public function handlePage($page) { //打印處當前頁面的title $res = $page->sel('//title'); for ($i = 0; $i < count($res); ++$i) { echo $res[$i]->plaintext; echo "\n"; } } } $crawler = new mycrawler(); $arrJobs = array( //任務的名字隨便起,這裏把名字叫qqnews //the key is the name of a job, here names it qqnews 'qqnews' => array( 'start_page' => 'http://news.qq.com/a/20140927/026557.htm', //起始網頁 'link_rules' => array( /* * 所有在這裏列出的正則規則,僅僅要能匹配到超連接,那麼那條爬蟲就會爬到那條超連接 * Regex rules are listed here, the crawler will follow any hyperlinks once the regex matches */ ), //爬蟲從開始頁面算起。最多爬取的深度,設置爲1表示僅僅爬取起始頁面 //Crawler's max following depth, 1 stands for only crawl the start page 'max_depth' => 1, ) , ); //$crawler->setFetchJobs($arrJobs)->run(); 這一行的效果和如下兩行的效果同樣 $crawler->setFetchJobs($arrJobs); $crawler->run();

將這個腳本和「phpfetcher.php」以及「Phpfetcher」文件夾放在同一個文件夾下(或者將「phpfetcher.php」和「Phpfetcher」放到你的PHP環境默認include的查找路徑),運行這個腳本,獲得的輸出例如如下:
[root@reetsee demo]# php single_page.php 
王思聰迴應遭警方調查:帶弓箭不犯法 我是綠箭俠_新聞_騰訊網
查看一下咱們抓取的網頁源碼。可以發現是如下這幾行中的title標籤內容提取出來了:
<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=gb2312"></meta>
        <meta charset="gb2312"></meta>
        <title>
            王思聰迴應遭警方調查:帶弓箭不犯法 我是綠箭俠_新聞_騰訊網
        </title>
上面就是一個最簡單的樣例。  ****** 實例2:multi_page.php ******接下來就是另一個簡單的樣例,好比說騰訊新聞的主頁,上面有各類新聞,咱們此次的目標是把騰訊新聞主頁( http://news.qq.com)顯示的部分新聞標題抓下來。直接先上例程:
<?

php //如下兩行使得這個項目被下載下來後本文件能直接執行 $demo_include_path = dirname(__FILE__) . '/../'; set_include_path(get_include_path() . PATH_SEPARATOR . $demo_include_path); require_once('phpfetcher.php'); class mycrawler extends Phpfetcher_Crawler_Default { public function handlePage($page) { //打印處當前頁面的第1個h1標題內榮(下標從0開始) $strFirstH1 = trim($page->sel('//h1', 0)->plaintext); if (!empty($strFirstH1)) { echo $page->sel('//h1', 0)->plaintext; echo "\n"; } } } $crawler = new mycrawler(); $arrJobs = array( //任務的名字隨便起。這裏把名字叫qqnews //the key is the name of a job, here names it qqnews 'qqnews' => array( 'start_page' => 'http://news.qq.com', //起始網頁 'link_rules' => array( /* * 所有在這裏列出的正則規則,僅僅要能匹配到超連接,那麼那條爬蟲就會爬到那條超連接 * Regex rules are listed here, the crawler will follow any hyperlinks once the regex matches */ '#news\.qq\.com/a/\d+/\d+\.htm$#', ), //爬蟲從開始頁面算起,最多爬取的深度,設置爲2表示爬取深度爲1 //Crawler's max following depth, 1 stands for only crawl the start page 'max_depth' => 2, ) , ); $crawler->setFetchJobs($arrJobs)->run(); //這一行的效果和如下兩行的效果同樣 //$crawler->setFetchJobs($arrJobs); //$crawler->run();

相比於第1個樣例,變化的地方有幾個:首先此次咱們添加了一條爬蟲跟蹤的規則「#news\.qq\.com/a/\d+/\d+\.htm$#」(注:PHP使用pcre正則表達式,可以到 PHP關於正則表達式的頁面看一下)。這是一個正則表達式。好比這樣的超連接「news.qq.com/a/12345678/00234.htm」那麼爬蟲就會跟蹤。而後是咱們把爬蟲的最大跟蹤深度設置爲2,這樣爬蟲會跟蹤1次起始頁面上符合要求的超級連接;最後是我把本來的Dom選擇從「//title」改成了「//h1」。意思就是抓取h1標籤的內容而不是像以前那樣抓取title標籤,想知道這樣的Dom選擇器的選擇規則,需要了解一下 xpath。執行這個文件,可以看到大體效果例如如下: phpfetcher_multipage  這樣第二個樣例就結束了。

臨時我就介紹這兩個樣例吧,Phpfetcher的源碼在這裏:https://github.com/fanfank/phpfetcher把代碼下載下來後。demo內的東西就可以直接執行了(固然你需要一個有curl和mb_string擴展的php,可以使用「php -m」命令來看一下你的PHP有沒有裝這兩個擴展)。

3 後話

實際上這個phpfetcher眼下還有很是多問題,性能應該是比較差的,只是畢竟也是我寫的第一個框架。另外是關於phpfetcher我有很是多東西尚未提到,好比Page對象的一些設置,Crawler對象的設置等,主要是眼下太過懶不想寫文檔,也不知道有沒有必要寫。我感受這個框架仍是蠻簡單的,裏面基本的函數我都作了具體的凝視,歡迎閱讀批評指正給建議!最後就是,假設你想寫個爬蟲,又想用PHP來寫,最好仍是試一下phpfetcher。 祝你們國慶節快樂~!  
相關文章
相關標籤/搜索