zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    hdu 5446 Unknown Treasure lucas和CRT
    Hdu 5444 Elven Postman dfs
    hdu 5443 The Water Problem 线段树
    hdu 5442 Favorite Donut 后缀数组
    hdu 5441 Travel 离线带权并查集
    hdu 5438 Ponds 拓扑排序
    hdu 5437 Alisha’s Party 优先队列
    HDU 5433 Xiao Ming climbing dp
    hdu 5432 Pyramid Split 二分
    Codeforces Round #319 (Div. 1) B. Invariance of Tree 构造
  • 原文地址:https://www.cnblogs.com/bkhdd/p/13224890.html
Copyright © 2011-2022 走看看