scrapy-Redis就是结合了分布式数据库redis,重写了scrapy一些比较关键的代码,将scrapy变成一个可以在多个主机上同时运行的分布式爬虫。
scrapy-redis是github上的一个开源项目,可以直接下载到他的源代码:
https://github.com/rolando/scrapy-redis
scrapy-redis 详解
scrapy-redis流程图
redis的使用
参考前文写的redis交互使用:Python | Python学习之Redis交互详解
scrapy-redis example-project
scrapy-redis的源码中提供了scrapy-redis的示例项目,我们下载下来学习一下。
https://github.com/rmax/scrapy-redis/tree/master/example-project
在example-project
中有三个demo,分别是dmoz
,myspider_redis
,以及mycrawler_redis
。
本次主要是对dmoz
这个demo进行学习和实战练习。
dmoz spider文件解析
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class DmozSpider(CrawlSpider):
"""Follow categories and extract links."""
name = 'dmoz'
allowed_domains = ['dmoztools.net']
start_urls = ['http://dmoztools.net/']
rules = [
Rule(LinkExtractor(
restrict_css=('.top-cat', '.sub-cat', '.cat-item')
), callback='parse_directory', follow=True),
]
def parse_directory(self, response):
for div in response.css('.title-and-desc'):
yield {
'name': div.css('.site-title::text').extract_first(),
'description': div.css('.site-descr::text').extract_first().strip(),
'link': div.css('a::attr(href)').extract_first(),
}
可以看到,dmoz项目和我们平时创建的scrapy项目并没有太大的区别,之所以能够实现持久化爬虫主要的不同之处在setting中设置了去重类和scheduler队列。
dmoz setting文件解析
上面提到的setting中设置了去重类和scheduler队列的操作主要就是在setting文件中添加下面这些代码。
# 去重类--指定哪个去重方法给request对象去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 队列--指定scheduler队列,调度器内存的是待爬取链接和已爬取对象指纹。
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 队列内容是否持久化保存--为False的时候,关闭redis的时候清空redis
SCHEDULER_PERSIST = True
REDIS_URL="redis://127.0.0.1:6379"
dmoz redis 数据库存取项
我们运行一下这个示例项目,并打开redis数据库,查看爬取到的结果。redis数据库中出现以下三个键,分别是:
dmoz request: 待爬取项
(先把爬取对象序列化存入数据库,再反序列化成爬取对,Scheduler队列,存放的待请求的request对象,获取的过程是pop操作,即获取一个会去除一个)
dmoz items:爬取的内容
(通过scrapy_redis.pipelines.RedisPipeline保存,屏蔽之后可以实现自定义对象存取位置,存放的获取到的item信息,在pipeline中开启RedisPipeline才会存入)
dmoz dumpfilter:抓到过的request对象指纹
(指纹集合,存放的是已经进入scheduler队列的request对象的指纹,指纹默认由请求方法,url和请求体组成)
dumpfilter的数量减去request的数量是已经抓爬取过的数量
关闭redispipeline之后,redis数据库中数据量变化:
- dmoz:requests 有变化(变多或者变少或者不变)
- dmoz:dupefilter 变多
- dmoz:items 不变
redispipeline中仅仅实现了item数据存储到redis的过程,我们可以新建一个pipeline(或者修改默认的ExamplePipeline),让数据存储到任意地方,但是权重应该小于redis存储的pipline。
scrapy-redis 源码详解
scrapy redis 如何生成指纹的?
import hashlib
f = hashlib.hsa1()
f.update(url.encode())
f.hexdigest()
scrapy-redis 判断request对象是否入队
def enqueue_request(self, request):
if not request.dont_filter and self.df.request_seen(request):
# dont_filter=False Ture True request指纹已经存在 #不会入队
# dont_filter=False Ture False request指纹已经存在 全新的url #会入队
# dont_filter=Ture False #会入队
self.df.log(request, self.spider)
return False
if self.stats:
self.stats.inc_value('scheduler/enqueued/redis', spider=self.spider)
self.queue.push(request)
return True
- dont_filter = True ,构造请求的时候,把dont_filter置为True,该url会被反复抓取(url地址对应的内容会更新的情况)
- 一个全新的url地址被抓到的时候,构造request请求
- url地址在start_urls中的时候,会入队,不管之前是否请求过
- 构造start_url地址的请求时候,dont_filter = True
scrapy-redis如何去重
fp = hashlib.sha1()
fp.update(to_bytes(request.method)) #请求方法
fp.update(to_bytes(canonicalize_url(request.url))) #请求链接
fp.update(request.body or b'') # 请求体
return fp.hexdigest()
- 使用sha1加密request得到指纹
- 把指纹存在redis的集合中
- 下一次新来一个request,同样的方式生成指纹,判断指纹是否存在reids的集合中
判断数据是否存在redis的集合中,不存在插入
added = self.server.sadd(self.key, fp)
return added != 0
scrapy-redis实战京东图书
爬取结果截图
页面分析
分析分类聚合页
打开待爬取页面:
https://book.jd.com/booksort.html
如下图:
分析分类聚合页
查看页面源代码,发现待爬取的内容存在其中,所以我们可以通过分析源码写出提取相应字段的xpath。
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
简历模板![在这里插入图片描述](https://img-blog.csdnimg.cn/646863996ac44da8af500c049bb72fbd.png#pic_center)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!