phpQuery采集網站數據


使用php采集網頁數據一般有多種方法,有時候會使用正則去采集頁面,但是當我們需要采集的頁面大並且多的話,會嚴重的浪費我們的cpu,這時候我們可以使用phpQuer來進行采集,不知道phpQuery的童鞋可以去看看這是東西

以采集 http://www.rsq111.com/goods.php?id=15663 這個網站為例

假設我們需要采集商品的 分類 名稱 價格 貨號 上架時間 商品圖片 詳情圖片

1.首先下載phpQuery類  phpQuery.php  https://www.php.cn/xiazai/leiku/233

2.接下來我們可以新建一個cj.php類

單頁面采集

<?php

header("Content-Type: text/html; charset=UTF-8");
require("phpQuery.php"); //引入類

    //檢測當前鏈接是否合法
    $url = 'http://www.rsq111.com/goods.php?id=15663';
    $header_info=getHeaders($url,true);
    if ($header_info != 200) {
        die;
    }

    phpQuery::newDocumentFile($url); //獲取網頁對象內容
   //pq() == $(this)
// 商品分類 $arr_check = pq(".breadcrumb"); foreach ($arr_check as $li) { $cat = pq($li)->text(); } $category = explode('>', $cat); //商品標題 $h1_check = pq("#name"); $title = pq($h1_check)->text(); //商品價格 $price_check = pq(".rmbPrice"); $shop_price = []; foreach ($price_check as $li) { $shop_price[] = pq($li)->text(); } $shop_price = array_pop($shop_price); $shop_price = explode('', $shop_price); $price = $shop_price[1]; //商品參數 $prame_check = pq("#summary1 .dd"); $prame = []; foreach ($prame_check as $li) { $prame[] = pq($li)->text(); } $sn = $prame[0];//貨號 $brank = $prame[1];//品牌 $time = $prame[2];//上架時間 // 商品圖片 $prame_photo_check = pq("#goods_gallery a"); $photo = []; foreach ($prame_photo_check as $li) { $src = 'http://www.rsq111.com/'.pq($li)->attr('href');//圖片路徑 //注釋代碼為保存圖片路勁,下載圖片到本地 $localSrc = 'w/'.md5($src).'.jpg'; // $stream = file_get_contents($src); // file_put_contents($localSrc,$stream); // pq($li)->attr('src',$localSrc); $photo[] = $localSrc; } //商品詳情圖片 $info_photo_check = pq(".detail-content img"); $info_photo = []; foreach ($info_photo_check as $li) { $src = 'http://www.rsq111.com/'.pq($li)->attr('src'); $localSrc = 'w/'.md5($src).'.jpg'; // $stream = file_get_contents($src); // file_put_contents($localSrc,$stream); // pq($li)->attr('src',$localSrc); $info_photo[] = $localSrc; } $data= [ 'title' => $title, 'category1' => $category[1], 'category2' => $category[2], 'category3' => $category[3], 'price' => $price, 'sn' => $sn, 'brank' => $brank, 'time' => $time, 'photo' => $photo, 'info_photo' =>$info_photo, ]; } echo "<pre>"; print_r($data);
//檢測url是否合法 function getHeaders($url,$data
=FALSE){ $_headers = get_headers($url,1); if( !$data ){return $_headers;} $curl = curl_init(); curl_setopt($curl,CURLOPT_URL,$url);//獲取內容url curl_setopt($curl,CURLOPT_HEADER,1);//獲取http頭信息 curl_setopt($curl,CURLOPT_NOBODY,1);//不返回html的body信息 curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);//返回數據流,不直接輸出 curl_setopt($curl,CURLOPT_TIMEOUT,30); //超時時長,單位秒 curl_exec($curl); $rtn= curl_getinfo($curl,CURLINFO_HTTP_CODE); curl_close($curl); return $rtn; }

這樣的話就可以采集到這頁面的數據了,但是如果我們需要采集的數據頁面比較多,比如上萬條數據的話,我們用這種方式速度會很慢

多頁面采集

如果我們直接循環去獲取頁面的,這樣每個頁面都需要訪問一次,並且抓取數據,耗時耗性能,這是我們可以有多種方案來優化提升速度

a.使用curl模擬多線程,將網頁一次性全部抓取回來,保存到本地進行采集,避免了重復請求,造成的開銷

b.使用swoole,創建多個線程,來進行采集,比如當我們去采集10個頁面的時候,耗時10秒,這時候我們創建多個線程,同事去請求分配出去的url,則可以提升我們的速度

c.當然,如果我們對數據要求性低,我們可以借助第三方軟件,比如八爪魚,火車,這些工具,可以更加快速的采集到需要的數據

筆者在這里采用的是第一種方法,因為是windows環境,swoole的話,windows安裝有點麻煩

我采用的是ajax輪詢,每次10條,比如我們從商品id為1的數據開始采集

phpcj.php

<?php

//獲取開始采集的id $start_id
= $_POST['start_id']; $end_id = $start_id+10; //每次加10條 if(empty($start_id) || empty($end_id)){ exit(json_encode(['status'=>0,'msg'=>'參數不正確'])); } $pdo = new PDO('mysql:host=數據庫地址;dbname=數據庫名','用戶','密碼',array(PDO::ATTR_PERSISTENT)); header("Content-Type: text/html; charset=UTF-8"); require("phpQuery.php");
//將要采集的地址全部循環出來
for ($i=$start_id; $i < $end_id; $i++) { $urls[$i] = 'http://www.rsq111.com/goods.php?id='.$i; } //判斷當前url是否合法,這里我判斷的是第一條 $code = getHeaders(array_shift($urls),true); if($code != 200){
  //如果不合法,返回結束id,重新開始執行 exit(json_encode([
'status'=>1,'msg'=>'當前id無商品','end_id'=>$end_id])); } $save_to='test.txt'; // 把抓取的代碼寫入該文件 $st = fopen($save_to,'w+'); $mh = curl_multi_init(); foreach ($urls as $i => $url) { $conn[$i] = curl_init($url); curl_setopt($conn[$i], CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); curl_setopt($conn[$i], CURLOPT_HEADER ,0); curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT,60); curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,true); // 設置不將爬取代碼寫到瀏覽器,而是轉化為字符串 curl_multi_add_handle ($mh,$conn[$i]); } do { curl_multi_exec($mh,$active); } while ($active); foreach ($urls as $i => $url) { file_put_contents($save_to, ''); $data = curl_multi_getcontent($conn[$i]); // 獲得爬取的代碼字符串 file_put_contents($save_to, $data); //將抓取到的野蠻寫入到文件中 $data = cj($i); if ($data) { $add[$i] = $data; } } foreach ($urls as $i => $url) { curl_multi_remove_handle($mh,$conn[$i]); curl_close($conn[$i]); } curl_multi_close($mh); fclose($st); //將采集成功的數據存入數據庫 $sql = ''; if(!empty($add)) { foreach ($add as $key => $value) { $title = str_replace("'","",$value['title']); $category1 = $value['category1']; $category2 = $value['category2']; $category3 = $value['category3']; $price = $value['price']; $sn = $value['sn']; $brank = $value['brank']; $time = $value['time']; $photo = $value['photo']; $info_photo = $value['info_photo']; $cj_id = $end_id; $sql[] = "('$title','$category1','$category2','$category3','$price','$sn','$brank','$time','$photo','$info_photo','$cj_id')"; } $sqls =implode(',', $sql); $add_sql = "INSERT into phpcj (title,category1,category2,category3,price,sn,brank,time,photo,info_photo,cj_id) VALUES ".$sqls; $res = $pdo->exec($add_sql); if(!$res) {
    //采集未成功,返回id,重新開始采集 exit(json_encode([
'status'=>0,'msg'=>'本次采集未成功..','start_id'=>$start_id])); }else{
    //采集成功,將最后一條數據返回,用作下此次執行的開始id exit(json_encode([
'status'=>1,'msg'=>'采集成功,正在進行循環采集..','end_id'=>$end_id])); } } //采集方法 function cj($i) { $url = 'http://www.***.com/test.txt'; //頁面存取的文本路勁 phpQuery::newDocumentFile($url); // 分類 $arr_check = pq(".breadcrumb"); foreach ($arr_check as $li) { $cat = pq($li)->text(); } if(empty($cat)){ return; } $category = explode('>', $cat); //標題 $h1_check = pq("#name"); $title = pq($h1_check)->text(); //價格 $price_check = pq(".rmbPrice"); $shop_price = []; foreach ($price_check as $li) { $shop_price[] = pq($li)->text(); } $shop_price = array_pop($shop_price); $shop_price = explode('', $shop_price); $price = $shop_price[1]; //參數 $prame_check = pq("#summary1 .dd"); $prame = []; foreach ($prame_check as $li) { $prame[] = pq($li)->text(); } $sn = $prame[0];//貨號 if(count($prame) > 2){ $brank = $prame[1];//品牌 $time = $prame[2];//上架時間 }else{ $brank = ''; $time = $prame[1];//上架時間 } // 商品圖片 $prame_photo_check = pq("#goods_gallery a"); $photo = []; foreach ($prame_photo_check as $li) { $src = 'http://www.rsq111.com/'.pq($li)->attr('href'); // $localSrc = 'w/'.md5($src).'.jpg'; // $stream = file_get_contents($src); // file_put_contents($localSrc,$stream); // pq($li)->attr('src',$localSrc); // $photo[] = $localSrc; $photo[] = $src; } $photo =json_encode($photo); //商品詳情圖片 $info_photo_check = pq(".detail-content img"); $info_photo = []; foreach ($info_photo_check as $li) { $src = 'http://www.rsq111.com/'.pq($li)->attr('src'); // $localSrc = 'w/'.md5($src).'.jpg'; // $stream = file_get_contents($src); // file_put_contents($localSrc,$stream); // pq($li)->attr('src',$localSrc); // $info_photo[] = $localSrc; $info_photo[] = $src; } $info_photo = json_encode($info_photo);
 //如果商品沒有三級分類,給他賦值為空
if(count($category) < 3){ $category[3] = ''; } $data = [ 'title' => $title, 'category1' => $category[1], 'category2' => $category[2], 'category3' => $category[3], 'price' => $price, 'sn' => $sn, 'brank' => $brank, 'time' => $time, 'photo' => $photo, 'info_photo' =>$info_photo, 'cj_id' => $end_id, ]; return $data; } //判斷url是否合法 function getHeaders($url,$data=FALSE){ $_headers = get_headers($url,1); if( !$data ){return $_headers;} $curl = curl_init(); curl_setopt($curl,CURLOPT_URL,$url);//獲取內容url curl_setopt($curl,CURLOPT_HEADER,1);//獲取http頭信息 curl_setopt($curl,CURLOPT_NOBODY,1);//不返回html的body信息 curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);//返回數據流,不直接輸出 curl_setopt($curl,CURLOPT_TIMEOUT,30); //超時時長,單位秒 curl_exec($curl); $rtn= curl_getinfo($curl,CURLINFO_HTTP_CODE); curl_close($curl); return $rtn; }

這樣我們完成了對頁面的循環采集

前台代碼,使用ajax循環請求(如果,使用服務器定時任務的話,需要注意,對采集不成功的判斷,這塊我是手動重新填寫id,因為采集的因素不可控,也許對方頁面錯誤,對方的數據庫出錯,但是我們依舊可以正常訪問到,所以需要對采集不成功,或者對某個id一直進行采集時,我們要加時效性判斷。如果超過多長時間,默認為當前數據采集不成功,則開始下一輪的采集,可以是當前id+1,或者其他規則,總之跳過這個id就可以)

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
      <input type="text" name="start_id" id="start_id" placeholder="采集開始id">
      <!-- <input type="text" name="end_id" id="end_id" placeholder="采集結束id"> -->
      <input type="button" id="btn" value="開始采集">
      <h5 id="zhi"></h5>
      <input type="text" id="ids" placeholder="采集返回成功條數">
</body>
</html>
<script type="text/javascript" src="./jquery.min.js"></script>
<script>
$('#btn').click(function(){
   var startid = $('#start_id').val();
   cj(startid)
})

function cj(startid)
{ 
    var ids = $('#ids').val();
    if (ids) {
      startid = ids;
    }
    
    $('#zhi').html('采集中...');
    var urls = "http://www.***.com/phpcj.php"
      $.ajax({
          type: "post",
          url: urls,
          dataType:'json',
          data: {"start_id":startid}, 
          success : function(res){
            console.log(res)
            $('#zhi').html('');
            if(res.status == 0){
                $('#zhi').html(res.msg);
                $('#ids').val(res.start_id);
            }else{
                $('#zhi').html(res.msg);
                $('#ids').val(res.end_id);
                setTimeout(cj,3*1000);
            }
            
              
          }
          
      });
}

</script>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM