天天看點

php抓取網頁資訊

symfony/dom-crawler+guzzlehttp/guzzle

1.安裝兩個元件

composer require guzzlehttp/guzzle
 composer require symfony/dom-crawler
           

Guzzle插件簡介

Guzzle 是一個 PHP 的 HTTP 用戶端,用來輕而易舉地發送請求,并內建到我們的 WEB 服務上。

接口簡單:建構查詢語句、POST 請求、分流上傳下載下傳大檔案、使用 HTTP cookies、上傳 JSON 資料等等。

發送同步或異步的請求均使用相同的接口。

使用 PSR-7 接口來請求、響應、分流,允許你使用其他相容的 PSR-7 類庫與 Guzzle 共同開發。

抽象了底層的 HTTP 傳輸,允許你改變環境以及其他的代碼,如:對 cURL與 PHP 的流或 socket 并非重度依賴,非阻塞事件循環。

中間件系統允許你建立構成用戶端行為。

symfony和dom-crawler

symfony我就不多說了,怎麼形容,實在不好說,國内生态弱,一個朋友說:Symfony 和 ZendFramework 基本上是為企業應用,大型複雜網際網路應用準備的。核心的思想大部分都是 Copy 了 Java 生态圈中一些成熟的模式等, 比如子產品化,企業應用架構模式。Doctrine 甚至 Copy 了 Hibernate,Bean Validation 等。就連 PSR 也是來自 JSR 的靈感,不得不說的 Symfony 為現在 PHP 架構 /元件互通互用作了很大貢獻。不懂 OOP,和不了解馬大叔的企業架構模式這些可能覺得 Symfony 太難了。但對于熟悉這些的 Java 程式員,Symfony 太友好了,上手幾乎不費吹灰之力。

dom-crawler:官方翻譯比較蹩腳:Crawler 類提供的方法用于查詢和操作HTML以及XML文檔。Crawler執行個體呈現的是一組 DOMElement 對象,它們是你可以輕松周遊的基本節點:總之是可以周遊節點的讀取dom的元件咯。

以下是我寫的一個demo參考一下

<?php

require_once './vendor/autoload.php';
header('Content-type:text/html;charset=UTF-8');
$Crawler = new \Symfony\Component\DomCrawler\Crawler();

class Command
{
    //抓取位址
    const URL = 'http://www.ccgp-liaoning.gov.cn/bulletin.do?method=showbulletin&bulletin_id=';

    //目前最大資料
    private $max_page = 0;

    //初始化擷取最大id
    public function __construct ()
    {
        $url      = 'http://www.ccgp-liaoning.gov.cn/bulletininfo.do?method=bdetail&treenum=05&treenumfalse=';
        $client   = new \GuzzleHttp\Client([
            'timeout' => 10 ,
        ]);
        $response = $client->request('GET' ,$url);
        // 轉換成頁面使用的編碼,預設為UTF-8,此網站亂碼。
        $type          = $response->getHeader('content-type');
        $parsed        = \GuzzleHttp\Psr7\parse_header($type);
        $original_body = (string)$response->getBody()->getContents();;
        $utf8_body = mb_convert_encoding($original_body ,'UTF-8' ,$parsed[0]['charset'] ? : 'UTF-8');
        $crawler   = new \Symfony\Component\DomCrawler\Crawler();
        $crawler->addHtmlContent($utf8_body);
        $err = $crawler->filterXPath('//tbody/tr')->first()->attr('id');
        if (!empty($err)) {
            $this->max_page = $err;
        } else {
            echo '暫無資料';
            exit;
        }
    }

    /**
     * @throws \GuzzleHttp\Exception\GuzzleException
     * 執行抓取
     */
    public function execute ()
    {
        header('Content-type:text/html;charset=UTF-8');
        //需要爬取的頁面
        $url = self::URL;
        //下載下傳網頁内容
        $client = new \GuzzleHttp\Client([
            'timeout' => 10 ,
        ]);
        $data   = [];
        //預設抓取30條
        for ($i = $this->max_page; $i >= $this->max_page - 30; $i--) {
            $response = $client->request('GET' ,$url . $i);
            // 轉換成頁面使用的編碼,預設為UTF-8,此網站亂碼。
            $type          = $response->getHeader('content-type');
            $parsed        = \GuzzleHttp\Psr7\parse_header($type);
            $original_body = (string)$response->getBody()->getContents();;
            $utf8_body = mb_convert_encoding($original_body ,'UTF-8' ,$parsed[0]['charset'] ? : 'UTF-8');
            $crawler   = new \Symfony\Component\DomCrawler\Crawler();
            $crawler->addHtmlContent($utf8_body);
            try {
                $err = $crawler->filterXPath('//*[@class="newinfotr1"]')->text();
                if (!empty($err)) {
                   //TODO 你的業務邏輯
                }
            } catch (\Exception $e) {

            }
        }
        print_r($data);
        exit;
    }

    /**
     * @param $str
     * @return string
     * 删除字元串中的空格
     */
    private function clearHtml ($str)
    {
        $str = trim($str); //清除字元串兩邊的空格
        $str = preg_replace("/\t/" ,"" ,$str); //使用正規表達式替換内容,如:空格,換行,并将替換為空。
        $str = preg_replace("/\r\n/" ,"" ,$str);
        $str = preg_replace("/\r/" ,"" ,$str);
        $str = preg_replace("/\n/" ,"" ,$str);
        $str = preg_replace("/ /" ,"" ,$str);
        $str = preg_replace("/  /" ,"" ,$str);  //比對html中的空格
        return trim($str); //傳回字元串
    }
}

//執行
$obj = new Command();
$obj->execute();