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>
原文地址:https://www.cnblogs.com/bkhdd/p/13224890.html