系列教程:

看完两篇,相信大家已经从开始的小菜鸟晋升为中级菜鸟了,好了,那我们就继续我们的爬虫课程。

上一课呢一定是因为对手太强,导致我们并没有完整的完成尚妆网的爬虫。

吭吭~,我们这一课继续,争取彻底搞定尚妆网,不留任何遗憾。

我们先回顾一下,上一课主要遗留了两个问题,两个问题都和ajax有关。

1、由于是ajax加载下一页,导致下一页url并不会被系统自动发现。

2、商品页面的价格是通过ajax加载的,我们直接从网页中获取不到信息本身。

好了,我们先解决第一个问题:

第一个问题实际上是一个爬虫中比较常见的问题,即url的发现,默认情况下,URL的发现是神箭手云爬虫框架自动处理的,但是如果在ajax的情况下,框架则无从发现url,这个时候就需要我们自己手动处理url的发现,这里,神箭手给我们提供了一个很方便的回调函数让我们来自己处理url的发现:

onProcessHelperUrl(url, content, site)

这个回调函数有两个参数,分别是当前处理的页面对象和整个爬取站的对象,我们可以通过获取页面对象的内容来分析是否有我们需要的新一页的url,通过site.addUrl()方法加入到url队列中既可。这里我们可以看到,当超出页数的时候,尚妆网会给我们返回一个这样的页面,我们就知道页数超过了,不需要在加入新的页url:

这个页面我们很好判断,只需要看内容中是否有"无匹配商品"关键字既可。

这里我们需要一些基础的js能力,代码如下:

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);

}

}

原理很简单,如果内容中没有无匹配商品这个关键词的时候,则把当前页面的下一页加入的待爬队列中。

好了,ajax分页问题彻底解决,下面来看这个最棘手的ajax内容加载的问题,也就是如何获取到商品页面中的价格信息

首先,遇到这类问题,我们通常有两个思路:

1、通过js引擎将整个页面渲染出来之后,在去做内容抽取,这个方案对于一些复杂js页面是唯一解决方案,用神箭手来处理也很简单,不过由于需要执行js,导致抓取速度很慢,不到不得已情况,我们先不使用这个核武器

2、通过刚刚处理分页的经验,我们可以预先分析ajax请求,然后将这一步多出来的请求和原来的页面请求做一个关联。这种方案适合比较简单的js页面中。

OK,介绍完思路,根据经验,我们感觉尚妆网的ajax加载并没有十分复杂,所以我们选择方案二来处理这种ajax页面加载。

同样的,首页我们通过chrome开发者工具,抓取到这个ajax请求,这里教大家一个小窍门,开发者工具中,可以筛选请求对象未xhr,这种就是异步请求,我们就很容易发现我们的嫌疑url:

http://item.showjoy.com/product/getPrice?skuId=22912

我们在页面中找一下这个22912怎么提取最方便,我们很快就发现了一个标签:

这个标签很干净,获取的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对应的值。

那最后我们怎么才能关联这个请求呢?这里也是框架中提供的一个方案,叫做attachedUrl,专门用来解决关联请求的请求的问题,也就是某一个字段的值可以通过一个关联请求的内容中抽取出来。语法我就不介绍了,直接上代码吧:

{

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)

函数会将抽取名和抽取到的数据传进来,我们只需要通过js的字符串处理函数对数据进行进一步加工既可,直接上完整的修改过的代码:

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();

我们判断了如果是comment和sales抽取项时,通过正则直接匹配到括号里的数字,这里注意,网页上的括号本来是全角的括号,所以千万不要写错了。

这次终于可以开心的看着自己的爬虫数据结果了:

对爬虫感兴趣的童鞋可以加qq群讨论:342953471。

某电商网站销售python图书_手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取...相关推荐

  1. 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫

    系列教程 手把手教你写电商爬虫-第一课 找个软柿子捏捏 如果没有看过第一课的朋友,请先移步第一课,第一课讲了一些基础性的东西,通过软柿子"切糕王子"这个电商网站好好的练了一次手,相 ...

  2. 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 1

    系列教程 手把手教你写电商爬虫-第一课 找个软柿子捏捏 如果没有看过第一课的朋友,请先移步第一课,第一课讲了一些基础性的东西,通过软柿子"切糕王子"这个电商网站好好的练了一次手,相 ...

  3. python k线合成_手把手教你写一个Python版的K线合成函数

    手把手教你写一个Python版的K线合成函数 在编写.使用策略时,经常会使用一些不常用的K线周期数据.然而交易所.数据源又没有提供这些周期的数据.只能通过使用已有周期的数据进行合成.合成算法已经有一个 ...

  4. python网络爬虫网易云音乐_手把手教你写网络爬虫(1):网易云音乐歌单

    大家好,<手把手教你写网络爬虫>连载开始了!在笔者的职业生涯中,几乎没有发现像网络爬虫这样的编程实践,可以同时吸引程序员和门外汉的注意.本文由浅入深的把爬虫技术和盘托出,为初学者提供一种轻 ...

  5. windows脚本编制引擎_手把手教你写脚本引擎(一)

    手把手教你写脚本引擎(一)--挑选语言的特性 陈梓瀚 华南理工大学软件本科05级 脚本引擎的作用在于增强程序的可配置性.从游戏到管理系统都需要脚本,甚至连工业级产品的Office.3DS Max以及A ...

  6. 永磁同步电机驱动视频教程_矢量控制_手把手教你写代码_无感FOC_有感FOC_状态观测器_卡尔曼滤波_慧驱动

    手把手教你驱动永磁同步电机_视频教程 前言 大家在刚开始搞永磁同步电机控制的时候,大部分都是先接触的芯片厂商提供的方案,然后查资料,买芯片厂商的电机套件,买回来后,通电启动,电机顺利的转起来了,然后再 ...

  7. python开发一个自己的技术网站_手把手教你写网站:Python WEB开发技术实战

    摘要:本文详细介绍了Python WEB开发的基础入门.以一个博客站点的开发为例讲解了基于Django框架开发WEB站点的全过程.通过本文的学习可以快速掌握基于Django的Python WEB的开发 ...

  8. js如何运行python代码_手把手教你如何使用Python执行js代码

    前言 各位小伙伴,大家好,这次咱们来说一下关于爬虫方向的一个知识,Python如何执行js,快来看看吧!!! 为什么要引出Python执行js这个问题? 都说术业有专攻,每个语言也都有自己的长处和短处 ...

  9. qq 音乐 python 登录_手把手教你使用Python抓取QQ音乐数据(第一弹)

    [一.项目目标] 获取 QQ 音乐指定歌手单曲排行指定页数的歌曲的歌名.专辑名.播放链接. 由浅入深,层层递进,非常适合刚入门的同学练手. [二.需要的库] 主要涉及的库有:requests.json ...

  10. python卸载_手把手教Python环境安装

    Anaconda集成环境 Python3.7 如果是linux环境包括MacOs,系统环境中会默认安装python2.7. 尽量量不不要卸载linux环境中的默认python环境,直接安装Python ...

最新文章

  1. 精品软件 推荐 硬盘物理序列号修改专家
  2. 使用脑电图慢皮层电位重建3D空间中的手,肘和肩的实际和想象的轨迹
  3. 【杂谈】什么是我心目中深度学习算法工程师的标准
  4. ubuntu系统下创建软件桌面快捷方式
  5. SQL内存优化-最大化使用内存
  6. vivo手机解锁_vivo“手术刀”再营业,OriginOS让手机做“减法”
  7. 硬纪元AI峰会前瞻:线下大数据驱动下的新零售,目标是精准营销
  8. STM8S 低功耗(1)
  9. Atitit 前端测试最简化内嵌web服务器 php 与node.js 目录 1.1. php内置Web Server 1 1.2. Node的 2 Node的比较麻烦些。。Php更加简单
  10. PID算法 旋转倒立摆与平衡车的区别。此贴后边会更新。
  11. DEVELOPMENT OF A LOW-COST VISION SYSTEM FOR FINDING CONTOUR AND SURFACE DEFECTS ON CAST IRON ENGINE
  12. Markdown编辑器 - 字体颜色表(颜色名、十六进制颜色值、颜色)
  13. 大数据时代下的迁移学习_重磅干货丨详解:学习迁移VS迁移学习大数据!
  14. Wildcard Matching 1
  15. Java时间操作类库—Joda-Time
  16. usb接口芯片ft245bm的功能及其应用
  17. 风变编程python26_风变编程学习Python的切身体会
  18. 生成器、迭代器、推导式——思维导图
  19. 文字保护纱-Material Design
  20. sqlserver wait millis 60003, active 0, maxActive 20, creating 0(String)

热门文章

  1. 火车采集 PHP插件 post,火车采集器2010版PHP插件增加扩展的方法
  2. 【服务器数据恢复】IBM服务器RAID控制器出错的数据恢复案例
  3. Error occurred during initialization of VM 解决
  4. 针对VC++ 上各种方法获取时间差,CSpanTime等
  5. 数组中的键值对去重_数组去重-
  6. PhotoShop中合并形状颜色会变化的问题
  7. centos 关机命令_全了 Linux 常用命令大汇集
  8. easyUI双击事件,完整总结
  9. Adobe ColdFusion
  10. Windows7驱动调试小Tips