Scrapy——分布式原理

关于Scrapy工作流程回顾

Scrapy单机架构

上图的架构其实就是一种单机架构,只在本机维护一个爬取队列,Scheduler进行调度,而要实现多态服务器共同爬取数据关键就是共享爬取队列。

分布式架构

将上图进行再次更改

这里重要的就是我的队列通过什么维护?

  • 关于爬取队列我们自然想到的是基于内存存储的Redis。它支持多种数据结构,如:列表、集合、有序集合等,存取的操作也非常简单。

  • Redis支持的这几种数据结构,在存储中都有各自优点:

    • 列表(list)有lpush()、lpop()、rpush()、rpop()方法,可以实现先进先出的队列和先进后出的栈式爬虫队列。

    • 集合(set)的元素是无序且不重复的,这样我们可以非常方便的实现随机且不重复的爬取队列。

    • 有序集合有分数表示,而Scrapy的Request也有优先级的控制,我们可以用它来实现带优先级调度的队列。

如何去重?

这里借助redis的集合,redis提供集合数据结构,在redis集合中存储每个request的指纹
在向request队列中加入Request前先验证这个Request的指纹是否已经加入集合中。如果已经存在则不添加到request队列中,如果不存在,则将request加入到队列并将指纹加入集合

 

如何防止中断?如果某个slave因为特殊原因宕机,如何解决?

  • 在Scrapy中,爬虫运行时的Request队列放在内存中。爬虫运行中断后,这个队列的空间就会被释放,导致爬取不能继续。

  • 要做到中断后继续爬取,我们可以将队列中的Request保存起来,下次爬取直接读取保存的数据既可继续上一次爬取的队列。

  • 在Scrapy中制定一个爬取队列的存储路径即可,这个路径使用JOB_DIR变量来标识,命令如下:

    scrapy crawl spider -s JOB_DIR=crawls/spider
  • 更多详细使用请详见官方文档:http://doc.scrapy.org/en/latest/topics/jobs.html

  • 在Scrapy中,我们实际是把爬取队列保存到本地,第二次爬取直接读取并恢复队列既可。

  • 在分布式框架中就不用担心这个问题了,因为爬取队列本身就是用数据库存储的,中断后再启动就会接着上次中断的地方继续爬取。

  • 当Redis的队列为空时,爬虫会重新爬取;当队列不为空时,爬虫便会接着上次中断支处继续爬取。

 

如何实现上述这种架构?

这里有一个scrapy-redis的库,为我们提供了上述的这些功能,scrapy-redis改写了Scrapy的调度器,队列等组件,利用他可以方便的实现Scrapy分布式架构
关于scrapy-redis的地址:https://github.com/rmax/scrapy-redis

 

搭建分布式爬虫

考官网地址:https://scrapy-redis.readthedocs.io/en/stable/

前提是要安装scrapy_redis模块:pip install scrapy_redis
这里的爬虫代码是用的之前写过的爬取知乎用户信息的爬虫

修改该settings中的配置信息:(一般设置标红出即可)

替换scrapy调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

添加去重的class
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

添加pipeline
如果添加这行配置,每次爬取的数据也都会入到redis数据库中,所以一般这里不做这个配置
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}

共享的爬取队列,这里用需要redis的连接信息
这里的user:pass表示用户名和密码,如果没有则为空就可以
REDIS_URL = 'redis://password@host:6379'

设置为为True则不会清空redis里的dupefilter和requests队列
这样设置后指纹和请求队列则会一直保存在redis数据库中,默认为False,一般不进行设置

SCHEDULER_PERSIST = True

设置重启爬虫时是否清空爬取队列
这样每次重启爬虫都会清空指纹和请求队列,默认设置为False不清空,在单机爬取时此配置比较方便,分布式爬取一般不用此配置。
SCHEDULER_FLUSH_ON_START=True

分布式

将上述更改后的代码拷贝的各个服务器,当然关于数据库这里可以在每个服务器上都安装数据,也可以共用一个数据,我这里方面是连接的同一个mongodb数据库,当然各个服务器上也不能忘记:
所有的服务器都要安装scrapy,scrapy_redis,pymongo

这样运行各个爬虫程序启动后,在redis数据库就可以看到如下内容,dupefilter是指纹队列,requests是请求队列

 

posted @ 2019-11-20 00:58  lanston  阅读(1388)  评论(0编辑  收藏  举报