爬蟲抓取頁面數據原理(php爬蟲框架有不少 )

爬蟲抓取頁面數據原理(php爬蟲框架有不少 )

1、總結

一、php爬蟲框架有不少,包括不少傻瓜式的軟件php

二、照之前寫過java爬蟲的例子來看,真的很是簡單,就是一個獲取網頁數據的類或者方法(這裏的話$handle = fopen($url, "r");$content = stream_get_contents($handle, -1);),而後就能夠獲取網頁上的html源代碼,而後取啥數據就用正則表達式來取好了 html

 

2、爬蟲抓取頁面數據原理

a、網頁的頁面源碼咱們能夠輕鬆得到 java

 

b、好比cnsd博客,文章的正文內容所有放在<article></article>當中,因此很是好獲取,此時咱們獲取的是html的頁面,不一樣網站標籤不一樣,具體看狀況就好node

 

c、html的數據自帶格式,因此直接放到數據庫便可,由於數據庫裏面存的也就是html數據,要顯示的話直接把這部分數據放到頁面上面來便可python

 

3、PHP爬蟲最全總結1

 

 爬蟲是我一直以來躍躍欲試的技術,如今的爬蟲框架不少,比較流行的是基於python,nodejs,java,C#,PHP的的框架,其中又以基於python的爬蟲流行最爲普遍,還有的已是一套傻瓜式的軟件操做,如八爪魚,火車頭等軟件mysql

 今天咱們首先嚐試的是使用PHP實現一個爬蟲程序,首先在不使用爬蟲框架的基礎上實踐也是爲了理解爬蟲的原理,而後再利用PHP的lib,框架和擴展進行實踐。git

全部代碼掛在個人github上。github

1.PHP簡單的爬蟲–原型

爬蟲的原理:web

  • 給定原始的url;
  • 分析連接,根據設置的正則表達式獲取連接中的內容;
  • 有的會更新原始的url再進行分析連接,獲取特定內容,周而復始。
  • 將獲取的內容保存在數據庫中(mysql)或者本地文件中

下面是網上一個例子,咱們列下來而後分析
main函數開始正則表達式

<?php
/** * 爬蟲程序 -- 原型 * * 從給定的url獲取html內容 * * @param string $url * @return string */
function _getUrlContent($url) {
    $handle = fopen($url, "r");
    if ($handle) {
        $content = stream_get_contents($handle, -1);
        //讀取資源流到一個字符串,第二個參數須要讀取的最大的字節數。默認是-1(讀取所有的緩衝數據)
        // $content = file_get_contents($url, 1024 * 1024);
        return $content;
    } else {
        return false;
    } 
} 
/** * 從html內容中篩選連接 * * @param string $web_content * @return array */
function _filterUrl($web_content) {
    $reg_tag_a = '/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\ ]*).*?>/';
    $result = preg_match_all($reg_tag_a, $web_content, $match_result);
    if ($result) {
        return $match_result[1];
    } 
} 
/** * 修正相對路徑 * * @param string $base_url * @param array $url_list * @return array */
function _reviseUrl($base_url, $url_list) {
    $url_info = parse_url($base_url);//解析url
    $base_url = $url_info["scheme"] . '://';
    if ($url_info["user"] && $url_info["pass"]) {
        $base_url .= $url_info["user"] . ":" . $url_info["pass"] . "@";
    } 
    $base_url .= $url_info["host"];
    if ($url_info["port"]) {
        $base_url .= ":" . $url_info["port"];
    } 
    $base_url .= $url_info["path"];
    print_r($base_url);
    if (is_array($url_list)) {
        foreach ($url_list as $url_item) {
            if (preg_match('/^http/', $url_item)) {
                // 已是完整的url
                $result[] = $url_item;
            } else {
                // 不完整的url
                $real_url = $base_url . '/' . $url_item;
                $result[] = $real_url;
            } 
        } 
        return $result;
    } else {
        return;
    } 
} 
/** * 爬蟲 * * @param string $url * @return array */
function crawler($url) {
    $content = _getUrlContent($url);
    if ($content) {
        $url_list = _reviseUrl($url, _filterUrl($content));
        if ($url_list) {
            return $url_list;
        } else {
            return ;
        } 
    } else {
        return ;
    } 
} 
/** * 測試用主程序 */
function main() {
    $file_path = "url-01.txt";
    $current_url = "http://www.baidu.com/"; //初始url
    if(file_exists($file_path)){
        unlink($file_path);
    }
    $fp_puts = fopen($file_path, "ab"); //記錄url列表
    $fp_gets = fopen($file_path, "r"); //保存url列表
    do {
        $result_url_arr = crawler($current_url);
        if ($result_url_arr) {
            foreach ($result_url_arr as $url) {
                fputs($fp_puts, $url . "\r\n");
            } 
        } 
    } while ($current_url = fgets($fp_gets, 1024)); //不斷得到url
} 
main();
?>

2.使用crul lib

Curl是比較成熟的一個lib,異常處理、http header、POST之類都作得很好,重要的是PHP下操做MySQL進行入庫操做比較省心。關於curl的說明具體能夠查看PHP官方文檔說明http://php.net/manual/zh/book.curl.php
不過在多線程Curl(Curl_multi)方面比較麻煩。

開啓crul
針對winow系統:
- php.in中修改(註釋;去掉便可)

extension=php_curl.dll

  • php文件夾下的libeay32.dll, ssleay32.dll, libssh2.dll 還有 php/ext下的php_curl4個文件移入windows/system32

使用crul爬蟲的步驟:
- 使用cURL函數的基本思想是先使用curl_init()初始化一個cURL會話;
- 接着你能夠經過curl_setopt()設置你須要的所有選項;
- 而後使用curl_exec()來執行會話;
- 當執行完會話後使用curl_close()關閉會話。

例子

<?php
$ch = curl_init("http://www.example.com/");
$fp = fopen("example_homepage.txt", "w");

curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);

curl_exec($ch);
curl_close($ch);
fclose($fp);
?>

一個完整點的例子:

<?php
/** * 將demo1-01換成curl爬蟲 * 爬蟲程序 -- 原型 * 從給定的url獲取html內容 * @param string $url * @return string */
function _getUrlContent($url) {
    $ch=curl_init();  //初始化一個cURL會話
    /*curl_setopt 設置一個cURL傳輸選項*/
    //設置須要獲取的 URL 地址
    curl_setopt($ch,CURLOPT_URL,$url);
    //TRUE 將curl_exec()獲取的信息以字符串返回,而不是直接輸出
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    //啓用時會將頭文件的信息做爲數據流輸出
    curl_setopt($ch,CURLOPT_HEADER,1);
    // 設置瀏覽器的特定header
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        "Host: www.baidu.com",
        "Connection: keep-alive",
        "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Upgrade-Insecure-Requests: 1",
        "DNT:1",
        "Accept-Language: zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4,en-US;q=0.2",
        /*'Cookie:_za=4540d427-eee1-435a-a533-66ecd8676d7d; */    
        ));
    $result=curl_exec($ch);//執行一個cURL會話
    $code=curl_getinfo($ch,CURLINFO_HTTP_CODE);// 最後一個收到的HTTP代碼
    if($code!='404' && $result){
       return $result;
    }
    curl_close($ch);//關閉cURL
} 
/** * 從html內容中篩選連接 * @param string $web_content * @return array */
function _filterUrl($web_content) {
    $reg_tag_a = '/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\ ]*).*?>/';
    $result = preg_match_all($reg_tag_a, $web_content, $match_result);
    if ($result) {
        return $match_result[1];
    } 
} 
/** * 修正相對路徑 * @param string $base_url * @param array $url_list * @return array */
function _reviseUrl($base_url, $url_list) {
    $url_info = parse_url($base_url);//解析url
    $base_url = $url_info["scheme"] . '://';
    if ($url_info["user"] && $url_info["pass"]) {
        $base_url .= $url_info["user"] . ":" . $url_info["pass"] . "@";
    } 
    $base_url .= $url_info["host"];
    if ($url_info["port"]) {
        $base_url .= ":" . $url_info["port"];
    } 
    $base_url .= $url_info["path"];
    print_r($base_url);
    if (is_array($url_list)) {
        foreach ($url_list as $url_item) {
            if (preg_match('/^http/', $url_item)) {
                // 已是完整的url
                $result[] = $url_item;
            } else {
                // 不完整的url
                $real_url = $base_url . '/' . $url_item;
                $result[] = $real_url;
            } 
        } 
        return $result;
    } else {
        return;
    } 
} 
/** * 爬蟲 * @param string $url * @return array */
function crawler($url) {
    $content = _getUrlContent($url);
    if ($content) {
        $url_list = _reviseUrl($url, _filterUrl($content));
        if ($url_list) {
            return $url_list;
        } else {
            return ;
        } 
    } else {
        return ;
    } 
} 
/** * 測試用主程序 */
function main() {
    $file_path = "./url-03.txt";
    if(file_exists($file_path)){
        unlink($file_path);
    }
    $current_url = "http://www.baidu.com"; //初始url
    //記錄url列表  ab- 追加打開一個二進制文件,並在文件末尾寫數據
    $fp_puts = fopen($file_path, "ab"); 
    //保存url列表 r-只讀方式打開,將文件指針指向文件頭
    $fp_gets = fopen($file_path, "r"); 
    do {
        $result_url_arr = crawler($current_url);
        echo "<p>$current_url</p>";
        if ($result_url_arr) {
            foreach ($result_url_arr as $url) {
                fputs($fp_puts, $url . "\r\n");
            } 
        } 
    } while ($current_url = fgets($fp_gets, 1024)); //不斷得到url
} 
main();
?>

要對https支持,須要在_getUrlContent函數中加入下面的設置:

curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ; 
curl_setopt($ch, CURLOPT_USERPWD, "username:password");    
curl_setopt($ch, CURLOPT_SSLVERSION,3); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

結果疑惑:
咱們經過1和2部分獲得的結果差別很大,第1部分能獲得四千多條url數據,而第2部分卻一直是45條數據。

還有咱們得到url數據可能會有重複的,這部分處理在個人github上,對應demo2-01.php,或者demo2-02.php

3.file_get_contents/stream_get_contents與curl對比

3.1 file_get_contents/stream_get_contents對比

  • stream_get_contents — 讀取資源流到一個字符串
    與 [file_get_contents()]同樣,可是 stream_get_contents() 是對一個已經打開的資源流進行操做,並將其內容寫入一個字符串返回
$handle = fopen($url, "r");
$content = stream_get_contents($handle, -1);//讀取資源流到一個字符串,第二個參數須要讀取的最大的字節數。默認是-1(讀取所有的緩衝數據)
  • file_get_contents — 將整個文件讀入一個字符串
$content = file_get_contents($url, 1024 * 1024);

【注】 若是要打開有特殊字符的 URL (好比說有空格),就須要使用進行 URL 編碼。

3.2 file_get_contents/stream_get_contents與curl對比

php中file_get_contents與curl性能比較分析一文中有詳細的對比分析,主要的對比如今列下來:
- fopen /file_get_contents 每次請求都會從新作DNS查詢,並不對 DNS信息進行緩存。可是CURL會自動對DNS信息進行緩存。對同一域名下的網頁或者圖片的請求只須要一次DNS查詢。這大大減小了DNS查詢的次數。因此CURL的性能比fopen /file_get_contents 好不少。

  • fopen /file_get_contents 在請求HTTP時,使用的是http_fopen_wrapper,不會keeplive。而curl卻能夠。這樣在屢次請求多個連接時,curl效率會好一些。

  • fopen / file_get_contents 函數會受到php.ini文件中allow_url_open選項配置的影響。若是該配置關閉了,則該函數也就失效了。而curl不受該配置的影響。

  • curl 能夠模擬多種請求,例如:POST數據,表單提交等,用戶能夠按照本身的需求來定製請求。而fopen / file_get_contents只能使用get方式獲取數據。

4.使用框架

使用框架這一塊打算之後單獨研究,並拿出來單寫一篇博客

全部代碼掛在個人github上。

參考閱讀:
- 我用爬蟲一天時間「偷了」知乎一百萬用戶,只爲證實PHP是世界上最好的語言
- 知乎 – PHP, Python, Node.js 哪一個比較適合寫爬蟲?
- 最近關於對網絡爬蟲技術總結
- PHP實現簡單爬蟲 (http://www.oschina.net/code/snippet_258733_12343)]
- 一個PHP實現的輕量級簡單爬蟲
- php中file_get_contents與curl性能比較分析
- PHP curl之爬蟲初步
- 開源中國-PHP爬蟲框架列表
- 網頁抓取:PHP實現網頁爬蟲方式小結,抓取爬蟲
- PHP爬蟲框架–PHPCrawl
- php安裝pcntl擴展實現多進程

閱讀更多
相關文章
相關標籤/搜索