您的位置:首页 > 理论基础 > 计算机网络

如何在神箭手上快速开发爬虫——第四课 如何爬取分页数据【蘑菇街商品评论】

2017-07-31 00:00 585 查看
注:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐