系列教程:
手把手教你写电商爬虫-第一课 找个软柿子捏捏
手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫
看完两篇,相信大家已经从开始的小菜鸟晋升为中级菜鸟了,好了,那我们就继续我们的爬虫课程。
上一课呢一定是因为对手太强,导致我们并没有完整的完成尚妆网的爬虫。
吭吭~,我们这一课继续,争取彻底搞定尚妆网,不留任何遗憾。
我们先回顾一下,上一课主要遗留了两个问题,两个问题都和ajax有关。
1、由于是ajax加载下一页,导致下一页url并不会被系统自动发现。
2、商品页面的价格是通过ajax加载的,我们直接从网页中获取不到信息本身。
好了,我们先解决第一个问题:
第一个问题实际上是一个爬虫中比较常见的问题,即url的发现,默认情况下,URL的发现是神箭手云爬虫框架自动处理的,但是如果在ajax的情况下,框架则无从发现url,这个时候就需要我们自己手动处理url的发现,这里,神箭手给我们提供了一个很方便的回调函数让我们来自己处理url的发现:
onProcessHelperUrl(url, content, site)
这个回调函数有两个参数,分别是当前处理的页面对象和整个爬取站的对象,我们可以通过获取页面对象的内容来分析是否有我们需要的新一页的url,通过site.addUrl()方法加入到url队列中既可。这里我们可以看到,当超出页数的时候,尚妆网会给我们返回一个这样的页面,我们就知道页数超过了,不需要在加入新的页url:
configs.onProcessHelperUrl = function(url, content, site){ if(!content.indexOf("无匹配商品")){ //如果没有到最后一页,则将页数加1 var currentPage = parseInt(url.substring(url.indexOf("&page=") + 6)); var page = currentPage + 1; var nextUrl = url.replace("&page=" + currentPage, "&page=" + page); site.addUrl(nextUrl); } }原理很简单,如果内容中没有无匹配商品这个关键词的时候,则把当前页面的下一页加入的待爬队列中。
<input type="hidden" value="22912" id="J_UItemId" />这个标签很干净,获取的xpath也很简单:
//input[@id="J_UItemId"]/@value
{"count":0,"data":{"discount":"6.2","discountMoney":"43.00","originalPrice":112,"price":"69.00","showjoyPrice":"69.00"},"isRedirect":0,"isSuccess":0,"login":0}可以看出来,是一个典型的json对象,这个就好办了,神箭手中给我们提供了通过jsonpath提取内容的方式,可以很简单的提取到价格对象,即price对应的值。
{ name: "skuid", selector: "//input[@id='J_UItemId']/@value", }, { name: "price", sourceType: SourceType.AttachedUrl, attachedUrl: "http://item.showjoy.com/product/getPrice?skuId={skuid}", selectorType: SelectorType.JsonPath, selector: "$.data.price", }简单介绍一下attachedUrl的用法,首先我们要设置sourceType为attachedUrl,同时我们要设置一个attachedUrl,即为关联请求的地址,其中由于有一个值是动态的,所以我们需要在这个抽取项之前先抽取一下这个动态的值,所以我们增加了一个抽取项的名字叫做skuid,在attachedUrl中的调用方法为{skuid},真实请求时,该项就会被自动替换成我们上一个skuid抽取项抽取到的值。接着,由于我们获取到的是json返回,因此我们抽取的方式应该是通过jsonpath,最后,写一个抽取规则既可,jsonpath比xpath更加简单,相信大家一看就懂了。
var configs = { domains: ["www.showjoy.com","list.showjoy.com","item.showjoy.com"], scanUrls: ["http://list.showjoy.com/search/?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C"], contentUrlRegexes: ["http://item\\.showjoy\\.com/sku/\\d+\\.html"], helperUrlRegexes: ["http://list\\.showjoy\\.com/search/\\?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C(\\&page=\\d+)?"],//可留空 fields: [ { // 第一个抽取项 name: "title", selector: "//h3[contains(@class,'choose-hd')]",//默认使用XPath required: true //是否不能为空 }, { // 第二个抽取项 name: "comment", selector: "//div[contains(@class,'dtabs-hd')]/ul/li[2]",//使用正则的抽取规则 required: false //是否不能为空 }, { // 第三个抽取项 name: "sales", selector: "//div[contains(@class,'dtabs-hd')]/ul/li[3]",//使用正则的抽取规则 required: false //是否不能为空 }, { name: "skuid", selector: "//input[@id='J_UItemId']/@value", }, { name: "price", sourceType: SourceType.AttachedUrl, attachedUrl: "http://item.showjoy.com/product/getPrice?skuId={skuid}", selectorType: SelectorType.JsonPath, selector: "$.data.price", } ] }; configs.onProcessHelperUrl = function(url, content, site){ if(!content.indexOf("无匹配商品")){ //如果没有到最后一页,则将页数加1 var currentPage = parseInt(url.substring(url.indexOf("&page=") + 6)); var page = currentPage + 1; var nextUrl = url.replace("&page=" + currentPage, "&page=" + page); site.addUrl(nextUrl); } return true; } var crawler = new Crawler(configs); crawler.start();
afterExtractField(fieldName, data)
var configs = { domains: ["www.showjoy.com","list.showjoy.com","item.showjoy.com"], scanUrls: ["http://list.showjoy.com/search/?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C"], contentUrlRegexes: ["http://item\\.showjoy\\.com/sku/\\d+\\.html"], helperUrlRegexes: ["http://list\\.showjoy\\.com/search/\\?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C(\\&page=\\d+)?"],//可留空 fields: [ { // 第一个抽取项 name: "title", selector: "//h3[contains(@class,'choose-hd')]",//默认使用XPath required: true //是否不能为空 }, { // 第二个抽取项 name: "comment", selector: "//div[contains(@class,'dtabs-hd')]/ul/li[2]",//使用正则的抽取规则 required: false //是否不能为空 }, { // 第三个抽取项 name: "sales", selector: "//div[contains(@class,'dtabs-hd')]/ul/li[3]",//使用正则的抽取规则 required: false //是否不能为空 }, { name: "skuid", selector: "//input[@id='J_UItemId']/@value", }, { name: "price", sourceType: SourceType.AttachedUrl, attachedUrl: "http://item.showjoy.com/product/getPrice?skuId={skuid}", selectorType: SelectorType.JsonPath, selector: "$.data.price", } ] }; configs.onProcessHelperUrl = function(url, content, site){ if(!content.indexOf("无匹配商品")){ //如果没有到最后一页,则将页数加1 var currentPage = parseInt(url.substring(url.indexOf("&page=") + 6)); var page = currentPage + 1; var nextUrl = url.replace("&page=" + currentPage, "&page=" + page); site.addUrl(nextUrl); } return true; } configs.afterExtractField = function(fieldName, data){ if(fieldName == "comment" || fieldName == "sales"){ var regex = /.*((\d+)).*/; return (data.match(regex))[1]; } return data; } var crawler = new Crawler(configs); crawler.start();