Contents
  1. 1. 分布式起因
  2. 2. 分布式设计
  3. 3. 分布式改良
  4. 4. 重构scrapy-redis

由于最近在一家数据服务公司实习,项目需要了解分布式,所以在这里基于scrapy的分布式总结一下爬虫的分布式实习

分布式起因

单机无法完成全部工作任务所以要使用集群加速完成工作任务

分布式有点像蚁群,一只蚂蚁举不起一只卡壳虫,但是几百只就能轻松的把他运回家

但是分布式设计必须科学,否则就像下面一样,一个和尚挑水,其他和尚围观

分工不合理,来源网络

分布式设计

分布式设计原理在于分工

首先我们来看看爬虫怎么进行分工,单个爬虫运行根据url获取响应报文,然后通过解析报文返回结果或者下一次爬取目标,如果单个爬虫我们只要在内存维持一个set变量记住爬取过的url,这就是scrapy默认的方法。

但是我们无数个爬虫由于不在同一个进程,无法共享变量,所以我们只要让一个“variable(变量)”能够被被所以爬虫共享到就完成了主要功能

现在我们来完善具体细节
要求:

  • 爬虫能够轻松读取所以已爬取变量
  • 爬虫能够加入已读取变量
  • 爬虫能够获取下一次请求具体参数

原则上我们可以使用内存映射来构建这个变量,但是读取,修改都不便利,所以可以先使用redis作为存贮变量的地方,使用redis提供的set我们替代scrapy框架的set变量。

现在我们已经决定我们要使用什么容器来存贮变量,接下来我们要考虑存什么变量。

我们先看scrapy-redis存贮了什么,分析源代码可知,scrapy-redis将返回的Requestpickle话存入数据库,并且计算这个Request的32位hash值存入redisset中过滤列表。

scrapy-redis通过修改scrapy的调度器(scheduler)让其当爬虫没有Request需要处理时在redis中提取Request,实现分布式。

我们来分析一下这种方法,爬虫在爬取的过程中从master端获取Request,并不断生成Requestmaster端,master只是一个redis数据库,负责对url去重,分发任务。

我们来比较一下直接存取url这种方法,这种方法好处在于,slaver能够从上一个Request中获取全部信息,假如上一个Request需要存取获取的表单提取地址,我们下一次爬虫发起Request就能从上一个Request中获取参数。

当然由于我们存贮的是Request,一个Request pickle化之后的字符串比较长,当我们的任务列表里面有很多Request的时候,redis占用的内存会非常巨大。

当然如果爬虫启动的够多,生成一个就能把任务被调度下去,那么这个任务列表就能稳定在一个可控的范围。

总结

每个爬虫即负责爬取数据,又负责生成下一个任务,即无主次之分,我们可以一次性在docker中启动上百个实例,我们只是用redis充当一个存放变量的地方。

但是这种方法也有一个缺点,我们不能自由的添加初始url,要想添加新的爬取任务,必须新建一个爬虫更新初始url,我们如果是想搭建一个自由添加url的爬虫,这种实现方式不大优雅。

分布式改良

我们要修改程序框架,达到随时可以添加要爬取新任务,然而不影响爬虫集群

爬虫框架

我们独立出来mastermaster负责生成Request去重以及任务调度,而slaver只负责从master获取任务爬取。

这种方法我们可以很轻松对master改良而不影响slaver,通过让master定时从数据库中获取新的任务生成到任务列表,我们可以轻松添加新的任务到slaver集群中去。

下一步我们就介绍如何修改scrapy-redis达到我们新框架需要

重构scrapy-redis

参考:
基于Redis的三种分布式爬虫策略

Contents
  1. 1. 分布式起因
  2. 2. 分布式设计
  3. 3. 分布式改良
  4. 4. 重构scrapy-redis