首頁  >  文章  >  後端開發  >  PHP爬蟲技術知識點總結

PHP爬蟲技術知識點總結

不言
不言原創
2018-04-03 11:33:131956瀏覽


在的爬蟲框架很多,比較流行的是基於python,nodejs,java,C#,PHP的的框架,其中又以基於python的爬蟲流行最為廣泛,還有的已經是一套傻瓜式的軟體操作,如八爪魚,火車頭等軟體。

 今天我們首先嘗試的是使用PHP實作一個爬蟲程序,首先在不使用爬蟲框架的基礎上實踐也是為了理解爬蟲的原理,然後再利用PHP的lib,框架和擴展進行實踐。



#1.PHP簡單的爬蟲–原型

爬蟲的原理:

  • #給定原始的url;

  • #分析鏈接,根據設定的正規表示式取得連結中的內容;

  • 有的會更新原始的url再進行分析鏈接,獲取特定內容,周而復始。

  • 將取得的內容保存在資料庫中(mysql)或本機檔案中

    #

下面是網路上一個例子,我們列下來然後分析 
##main<span style="margin:0px;padding:0px;max-width:100%;font-size:15px;"></span>函數開始

<?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 = &#39;/<[a|A].*?href=[\&#39;\"]{0,1}([^>\&#39;\"\ ]*).*?>/&#39;;    
$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"] . &#39;://&#39;;    
    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"];   
        if (is_array($url_list)) {       
         foreach ($url_list as $url_item) { 
         if (preg_match(&#39;/^http/&#39;, $url_item)) { 
                             // 已经是完整的url                $result[] = $url_item;            } else { // 不完整的url
                $real_url = $base_url . &#39;/&#39; . $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官方文檔,不過在多線程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()關閉會話。

範例

#$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); 
    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", 
       ));  

    $result=curl_exec($ch);//执行一个cURL会话    $code=curl_getinfo($ch,CURLINFO_HTTP_CODE);// 最后一个收到的HTTP代码    if($code!=&#39;404&#39; && $result){       
       return $result;    }    curl_close($ch);//关闭cURL} /** * 从html内容中筛选链接 * @param string $web_content  * @return array  */function _filterUrl($web_content) {    $reg_tag_a = &#39;/<[a|A].*?href=[\&#39;\"]{0,1}([^>\&#39;\"\ ]*).*?>/&#39;;   
   $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"] . &#39;://&#39;;    
     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"];   
    if (is_array($url_list)) { 
      foreach ($url_list as $url_item) { 
       if (preg_match(&#39;/^http/&#39;, $url_item)) {
                // 已经是完整的url                $result[] = $url_item;            } else { 
               // 不完整的url                $real_url = $base_url . &#39;/&#39; . $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 — 将整个文件读入一个字符串

<code style="margin:0px;padding:0px;max-width:100%;font-family:Consolas, Inconsolata, Courier, monospace;white-space:pre;"><span style="color:#4f4f4f;margin:0px;padding:0px;max-width:100%;">$content</span> = file_get_contents(<span style="color:#4f4f4f;margin:0px;padding:0px;max-width:100%;">$url</span>, <span style="margin:0px;padding:0px;max-width:100%;">1024</span> * <span style="margin:0px;padding:0px;max-width:100%;">1024</span>);<br><span style="font-family:'PingFang SC', 'Microsoft YaHei', SimHei, Arial, SimSun;color:#999999;margin:0px;padding:0px;max-width:100%;text-align:justify;background-color:rgb(238,240,244);">【注】 如果要打开有特殊字符的 URL (比如说有空格),就需要使用进行 URL 编码。</span></code>

3.2 file_get_contents/stream_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方式获取数据

相关推荐:

一个简单的开源PHP爬虫框架『Phpfetcher』

以上是PHP爬蟲技術知識點總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn