欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

爬取京东的一些思路

程序员文章站 2024-02-26 13:06:28
...

简介

在之前的一个爬取知乎问题和答案的项目中遇到了许许多多的问题,写下此篇文章作为总结和回顾

项目文章 http://blog.csdn.net/sinat_34200786/article/details/78770356

项目地址 https://github.com/Dengqlbq/JDSpider


框架划分

先分析一下项目要爬取的内容:
1. 商品详情
2. 商品评论
3. 评论总结

爬取商品详情首先得有商品详情页的url,然后再进入页面爬取数据

爬取京东的一些思路

注意:商品url可以简化,这对于后面的爬取很有用

https://item.jd.com/4624505.html?jd_pop=0e7d3959-5331-45e1-a308-e552908569cc&abt=0
简化为:
https://item.jd.com/4624505.html
抽象为:
https://item.jd.com/{0}.html

所以获取商品详情前得获取商品url,商品url的获取则在于京东的搜索页中
通过对比简化后的url可以发现,在搜索页中商品url的关键在于商品id

爬取京东的一些思路

所以要爬取商品详情先获取商品url,要获取商品url先获取商品id。商品详情在详情页,商品id在搜索页,并且一个搜索页有多个商品id。如果把商品id和商品详情的获取整合在一个爬虫中代码难免显得臃肿,所以将功能分到两个爬虫里面,最终的框架划分如下:

JDUrlsSpider    获取商品id并构造商品详情url和商品评论url
JDDetailSpider  获取商品详情和评论总结
JDCommentSpider 获取商品评论

Q:为什么JDUrlsSpider还要构造商品评论url?①
A:简单讲就是因为获取评论和获取详情一样需要一个入口url,详细的后面会讲到
Q:为什么详情和评论总结都划分到JDDetailSpider?②
A:后面会讲到


获取商品ID

商品id在搜索页,那么先分析搜索页url

爬取京东的一些思路

搜索页url

https://search.jd.com/Search?keyword=电脑&enc=utf-8&wq=电脑&pvid=5549914a587d4ab2949557695960da56

多翻几页后可以发现url里面的几个重要参数:

keyword     搜索关键词
wq          搜索关键词
page        当前页数
s           (这个不好描述,就是page * 60)

所以搜索页url抽象为:

https://search.jd.com/Search?keyword={0}&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq={1}&page={2}&s={3}&click=0

查看页面中的商品id后可以发现其实还是很好找的,都在li标签里面,class也是特殊的,所以写个xpath就能轻松提取。

爬取京东的一些思路

但是提取后你会发现只获取到了30个商品id,而搜索页中手动数一下怎么也有60个商品id,那剩下的30个哪去了?凭借经验可以判断那是异步加载出来的,在搜索页手动的滚动一下滚动条也可以发现确实如此。

开发者工具–>Network–>XHR,只要找到异步请求的网址就好办了

爬取京东的一些思路

爬取京东的一些思路

可以看到当滚动条差不多到底部后拦截到了一个异步请求,请求的url超长,请求的response则证实了这就是我们需要找的url

请求url:

https://search.jd.com/s_new.php?keyword=%E7%94%B5%E8%84%91&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E7%94%B5%E8%84%91&page=2&s=27&scrolling=y&log_id=1514895812.28592&tpl=1_M&show_items=4624505,1378536,5225346,5113808,4824715,4338107,4161503,4335139,4824733,4335674,5002534,5029717,4624543,4274539,5148309,1593516,5148275,3597549,5425401,5189400,5487527,4752515,5454888,5025869,5148299,5352358,5020872,5005929,3915351,5005927

对比之前获取到的30个商品id可以发现,请求url的show_items参数的值就是之气的30个商品id

多翻几页后可以发现url里面的几个重要参数:

keyword     搜索关键词
page        对比后发现就是当前搜索页的页数+1
show_items  第一批获取的30个商品id

所以请求url抽象为:

https://search.jd.com/s_new.php?keyword={0}&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page={1}&s=26&scrolling=y&log_id=1512092382.36606&tpl=1_M&show_items={2}

所以要获取搜索页中后30个商品id只需要将几个重要参数填好再构造请求然后从response里提取就行了。

获取商品id步骤:

构造搜索页url
获取前30个商品id
构造异步请求
获取后30个商品id

获取商品详情和评论总结

商品详情

要获取的详情数据为:
1. name
2. num
3. price
4. owner(店铺名)
5. jd_sel (是否京东精选)
6. global_buy (是否全球购)
7. flag (自营标志)

如果你的爬虫直接将某个商品详情页直接下载下来进行数据提取,你会发现price永远都是返回空值,按照一般经验判断price是异步请求的。

开发者工具–>Network–>XHR,这时你会发现找不到相关的异步链接。怎么办?price数据一开始不在详情页说明它肯定是后面才请求的数据,既然请求数据那肯定是有相关链接的,XHR那里没有就全部数据找一遍。

开发者工具–>Network–>ALL,仔细找找就能发现请求price数据的链接

爬取京东的一些思路

爬取京东的一些思路

请求url:

https://p.3.cn/prices/mgets?callback=jQuery3162769&type=1&area=1_72_2799_0&pdtk=&pduid=525462493&pdpin=&pin=null&pdbp=0&skuIds=J_1378536&ext=11000000&source=item-pc
简化为:
https://p.3.cn/prices/mgets?skuIds=J_1378536
抽象为:
https://p.3.cn/prices/mgets?skuIds=J_{0}

请求返回的是json数据,并且从图中可以看出 “p”所对应的就是price的数据

到这里商品详情的数据就全都获取了。

商品评论总结

①这里解释一下为什么商品详情和商品的评论总结会放在一起,这是因为在获取商品详情price数据时,查找请求price数据的链接过程中发现了一个有意思的链接——获取评论总结的链接

爬取京东的一些思路

爬取京东的一些思路

请求url:

https://club.jd.com/comment/productCommentSummaries.action?referenceIds=1378536&callback=jQuery5056364&_=1514983166800
简化为:
https://club.jd.com/comment/productCommentSummaries.action?referenceIds=1378536
抽象为:
https://club.jd.com/comment/productCommentSummaries.action?referenceIds={0}

可以看到请求返回的数据是非常详细的,对于这个意外收获当然是大方笑纳,所以在获取商品详情的时候就顺便把评论总结也搞定了。

获取商品详情和评论总结步骤:

下载商品详情页
获取商品详情
构造price的url
获取price数据
构造comment_excerpt的url
获取comment_excerpt数据

商品评论

一个商品有很多评论,所以商品评论肯定不会一下全部加载出来而是一部分一部分的加载,那么只需要先翻几页评论然后找请求链接就可以了。

开发者工具–>Network–>ALL
爬取京东的一些思路

爬取京东的一些思路

可以看到请求返回的数据包含10个评论和评论热词(每次都会返回),随便点开一个评论会发现数据也是很详细的

爬取京东的一些思路

可以发现评论确实是对应的

爬取京东的一些思路

请求url:

https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv34564&productId=1378536&score=0&sortType=5&page=1&pageSize=10&isShadowSku=0&rid=0&fold=1
简化为:
https://sclub.jd.com/comment/productPageComments.action?productId=1378536&score=0&sortType=5&page=1&pageSize=10
抽象为:
https://sclub.jd.com/comment/productPageComments.action?productId={0}&score=0&sortType=5&page={1}&pageSize=10

②这里就可以解释一下为什么JDUrlsSpider需要构造评论url了,可以看到抽象后的评论url需要productId和page两个参数,productId在JDUrlsSpider中直接就有数据,然后将page设为1就可以构造出获取评论的入口url。

说下sortType这个参数,你可以改成其他值试试,你会发现有些值是返回json数据有些不是,这里选择值为5是为了请求返回json数据方便解析,不过实际上证明会有小概率出现返回的不是json数据的情况。

这里还有个问题需要说明——我怎么知道可以获取多少评论?其实在返回数据中都会有一个maxPage的值,根据这里就可以知道我们可以获取多少页的评论了。

爬取京东的一些思路

获取商品评论步骤:

获取商品评论的入口url
以maxPage构造循环
构造url
获取数据
构造url...

优化

框架划分好了,框架各个部分的思路也有了,接下来只要编码就能把项目完成。
可是想一想项目其实有挺多地方可以优化的,举几个例子:
1. 增加总控
2. 分布式
3. 代理池

增加总控

在框架划分中各个功能已经独立出来:
1. JDUrlsSpider负责根据搜索页url获取该页所有商品id的获取并形成详情url和评论url
2. JDDetailSpider负责根据详情url获取商品详情和评论总结
3. JDCommentSpider负责根据评论url获取商品评论

结构图:

爬取京东的一些思路

其实很明显的JDUrlsSpider需要根据搜索页url才能知道去哪里获取商品id,如果我们的项目只爬取一个或两三个指定关键词商品则可以写在JDUrlsSpider的配置文件中,但项目考虑的是爬取大量不同关键词商品信息,所以应该增加一个总控端并且总控端应该具备以下功能:
1. 可随时修改关键词
2. 可指定页面数量

优化后的思路就是:
总控端根据配置好的信息不断将搜索页url抛出,JDUrlsSpider不断接收搜索页url进行处理后抛出详情url和评论url,JDDetailSpider和JDCommentSpider则根据相应url进行数据获取

优化后结构图:

爬取京东的一些思路

分布式

分布式可以解决性能和带宽的瓶颈
试想一下多台机器的多个爬虫一起启动,那爬取速度肯定比单机快得多。

分布式的思路:
1. Master负责url去重,分发,数据存储(数据也可以直接存在Slave机)
2. Slave负责从Master处获取url然后执行自己的任务

这样处理的分布式优点除了快之外,Slave机还可以省去很多配置,只要把代码复制过去直接运行就可以了。

要做成这样的分布式也很简单,scrapy-redis就可以轻松搞定

分布式结构图:

爬取京东的一些思路

代理池

如果我们的爬虫爬取过于频繁就会触发京东的反爬虫机制,简单粗暴的的服务器会直接封禁IP,只要是这个IP的访问都会直接拒绝,所以我们需要构建一个代理池来应对。

构建代理池可以自己去IP代理商那里买,也可以直接爬取网上免费的代理存起来需要的时候就拿出来用。
买代理优点是方便快捷,只需要调用代理商的API就可以获取代理IP,缺点是贵并且IP的可用性不高。
自己爬代理优点当然是免费了但缺点同样明显——代理IP的可用性超低,还要定期更新存储的代理,识别无效代理并丢弃等等一系列维护。

怎么办好呢?其实万能的Github上已经有很多开源的代理池了,原理都是爬取网上的免费代理,只不过别人已经帮你做好维护工作了,装好就能用。

这里推荐一个Github上的代理池项目:
https://github.com/jhao104/proxy_pool
如果你使用推荐的代理池最好就用gunicorn部署这样可以提高并发性能

注意:使用代理会使爬虫明显变慢,尤其是遇到劣质代理的时候,所以一般最好不用代理


相关标签: 京东 框架