如何在神箭手上快速开发爬虫——第四课 如何爬取分页数据【蘑菇街商品评论】
如何在神箭手上快速开发爬虫——第四课 如何爬取分页数据【蘑菇街商品评论】
数据工厂V 发表于4个月前
如何在神箭手上快速开发爬虫——第四课 如何爬取分页数据【蘑菇街商品评论】
  • 发表于 4个月前
  • 阅读 1
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

注:

1、本课完整的爬虫代码可以在神箭手示例代码中查看:http://www.shenjianshou.cn/index.php?r=demo/docs&demo_id=500006

2、如何在神箭手上运行代码,请查看文档:http://docs.shenjianshou.cn/overview/guide/develop/crawler.html

3、更详细的爬虫开发教程,请查看文档:http://docs.shenjianshou.cn/develop/summary/summary.html

 

 

大家好,我是神箭手的游牧老师~

今天继续给大家带来 如何在神箭手上快速开发爬虫 系列教程的第四课:如何爬取分页数据。

 

通过前三课的学习,相信大家爬爬文章、爬爬商品啥的已经很简单了(还不会的筒子面壁去( ̄▽ ̄)”)。那么今天呢,主要跟大家分享下爬取分页数据的方法。

分页数据指的是要爬取的数据在多个分页上,无法通过请求一个页面一次抽取出来。举个常见的栗子,就是电商商品的评论了:

如果要将每个商品的所有评论爬取为一个商品数据的一个字段,因为在商品的详情页内,评论是分页显示的,所以需要通过分别访问每页评论抽取。

如何在内容页中抽取分页数据,神箭手提供了两种方法:

 

第一种方法,使用field的attachedUrl,在数据抽取过程中分别获取每页评论再汇总

attachedUrl是神箭手提供的抽取异步请求数据的方式(http://docs.shenjianshou.cn/develop/configs/field.html#attachedUrl),所以可以使用attachedUrl先分别抽取不同分页的评论,然后再在回调函数中将数据汇总。

异步抽取分页评论的field代码:

{
        name: "comments",
        alias: "评价",
        selector: "//div[@id='sjs']/span", // 3、抽取出每页评价的内容
        repeated: true, 
        children: [
          {
              name: "page", // 页码
              selector: "//text()",
              required: true
          },
          {
              name: "page_comments", // 该页的评价
              sourceType: SourceType.AttachedUrl, // attachedUrl表示在抽取过程中另发请求,再从返回的数据中抽取数据
              attachedUrl: "http://shop.mogujie.com/ajax/pc.rate.ratelist/v1?pageSize=20&sort=1&isNewDetail=1&itemId={$.product_id}&type=1&page={page}",
              selectorType: SelectorType.JsonPath, // 返回的数据是json,使用JsonPath抽取数据
              repeated: true,
              selector: "$.data.list",
              children: [
                {
                    name: "create_time",
                    alias: "评价时间",
                    selectorType: SelectorType.JsonPath,
                    selector: "$.created"
                },
                {
                    name:"content",
                    alias: "评价内容",
                    selectorType: SelectorType.JsonPath,
                    selector:"$.content"
                },
                {
                    name:"author",
                    alias: "评价者",
                    selectorType: SelectorType.JsonPath,
                    selector:"$.userInfo.uname"
                },
                {
                    name:"stock",
                    alias: "购买信息",
                    selectorType: SelectorType.JsonPath,
                    selector:"$.stock",
                    repeated: true
                }
              ]
          }

 

把分页数据汇总到一个数组的代码:

configs.afterExtractPage = function(page, data) {
    if (!data.comments) return data;
    // 4、将抽取的每页评价数据拼成一个数组返回
    var comments = [];
    for (var i = 0; i < data.comments.length; i++) {
        var pageComments = data.comments[i];
        for (var j = 0; j < pageComments.page_comments.length; j++) {
            comments.push(pageComments.page_comments[j]);
        }
    }
    data.comments = comments;
    return data;
};

 

注:需要在抽取前先获取评论的总页数:

configs.afterDownloadPage = function(page, site){
    var matches = /shop\.mogujie\.com\/detail/.exec(page.url);
    if(matches){
      // 如果当前下载的页面是内容页,需要先将要在抽取过程中发送的请求链接(获取评价)信息添加到页面中,方便抽取
      
      // 1、首先从内容页获取评价的总数
      var commentsCount = extract(page.raw, "//span[contains(text()[1],'评价')]/span");
      commentsCount = parseInt(commentsCount);
      var commentsPageCount = Math.ceil(commentsCount/20); //根据总评价数算出总评价页数
      // 2、然后将评价的每个页码添加到内容页中返回处理
      var extraHTML = '<div id="sjs">'; // id设置为一个特殊的值,方便抽取
      for(var i=1;i<=commentsPageCount;i++){
        extraHTML+='<span>'+i+'</span>';
      }
      extraHTML+='</div>';
      var index = page.raw.indexOf("</body>");
            page.raw = page.raw.substring(0, index) + extraHTML + page.raw.substring(index);
    }
    return page;
};

 

第二种方法,先请求所有分页评论,再添加到内容页中进行抽取

在afterDownloadPage函数中,先通过requestUrl请求和获取所有分页评论数据,然后再把数据添加到内容页中返回:

configs.afterDownloadPage = function(page, site){
    if(!page.raw){
      return page;
    }
    var matches = /shop\.mogujie\.com\/detail\/(.+?)\?/.exec(page.url);
    if(matches){    
      // 1、首先从内容页获取评价的总数
      var commentsCount = extract(page.raw, "//span[contains(text()[1],'评价')]/span");
      commentsCount = parseInt(commentsCount);
      var commentsPageCount = Math.ceil(commentsCount/20); //根据总评价数算出总评价页数
      
      var extraHTML = '<div id="sjs">'; // id设置为一个特殊的值,方便抽取
      
      // 2、分别请求和获取所有分页的评论,并组合成一个html
      for(var index=1;index<=commentsPageCount;index++){
         var comment = site.requestUrl("http://shop.mogujie.com/ajax/pc.rate.ratelist/v1?pageSize=20&sort=1&isNewDetail=1&itemId="+matches[1]+"&type=1&page="+index);
         if(comment){
           var json = JSON.parse(comment);
           json = json.data.list;
           for(var i=0;i<json.length;i++){
             extraHTML+='<div id="comment">';
             extraHTML+='<span id="time">'+json[i].created+'</span>';
             extraHTML+='<span id="content">'+json[i].content+'</span>';
             extraHTML+='<span id="author">'+json[i].userInfo.uname+'</span>';
             extraHTML+='<div id="stock">';
             for(var j=0;j<json[i].stock.length;j++){
               extraHTML+='<span>'+json[i].stock[j]+'</span>';
             }
             extraHTML+='</div>';
             extraHTML+='</div>';
           }
         }
      }
      extraHTML+='</div>';
      
      // 3、将评论数据html添加到内容页html中返回
      var bodyIndex = page.raw.indexOf("</body>");
      page.raw = page.raw.substring(0, bodyIndex) + extraHTML + page.raw.substring(bodyIndex);
    }
    return page;
};

 

然后就可以很轻松地从field中抽取出来了:

{
        name: "comments",
        alias: "评价",
        selector: "//div[@id='sjs']/div", // 4、抽取评论
        repeated: true, 
        children: [
          {
            name: "create_time",
            alias: "评价时间",
            selector: "//span[@id='time']"
          },
          {
            name:"content",
            alias: "评价内容",
            selector: "//span[@id='content']"
          },
          {
            name:"author",
            alias: "评价者",
            selector: "//span[@id='author']"
          },
          {
            name:"stock",
            alias: "购买信息",
            selector: "//div[@id='stock']/span",
            repeated: true
          }
        ]
      }

 

简单对比一下:

1、第一种方式是在抽取过程中异步请求,然后通过回调函数汇总成一个数组;

2、第二种方式是在抽取前先提前获取所有评论数据,然后修改返回的内容页内容(把评论数据添加进去),再和其他数据一样抽取即可;

3、游牧老师建议大家使用第二种方式,因为自由度更大。

 

完整代码请看这里:http://www.shenjianshou.cn/index.php?r=demo/docs&demo_id=500006

共有 人打赏支持
粉丝 9
博文 24
码字总数 25887
×
数据工厂V
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: