基于Redis的三种分布式爬⾍策略 前⾔: 爬⾍是偏IO型的任务,分布式爬⾍的实现难度⽐分布式计算和分布式存储简单得多。 个⼈以为分布式爬⾍需要考虑的点主要有以下⼏个: ? 爬⾍任务的统⼀调度 ? 爬⾍任务的统⼀去重 ? 存储问题 ? 速度问题 ? ⾜够“健壮”的情况下实现起来越简单/⽅便越好 ? 最好⽀持“断点续爬”功能 Python分布式爬⾍⽐较常⽤的应该是scrapy框架加上Redis内存数据库,中间的调度任务等⽤scrapy-redis模块实现。 此处简单介绍⼀下基于Redis的三种分布式策略,其实它们之间还是很相似的,只是为适应不同的⽹络或爬⾍环境作了⼀些调整⽽已(如有错误欢迎留⾔拍砖)。
【策略⼀】 Slaver端从Master端拿任务(Request/url/ID)进⾏数据抓取,在抓取数据的同时也⽣成新任务,并将任务抛给Master。Master端只有⼀个Redis数据库,负责对Slaver提交的任务进⾏去重、加⼊待爬队列。 优点: scrapy-redis默认使⽤的就是这种策略,我们实现起来很简单,因为任务调度等⼯作scrapy-redis都已经帮我们做好了,我们只需要继承RedisSpider、指定redis_key就⾏了。 缺点: scrapy-redis调度的任务是Request对象,⾥⾯信息量⽐较⼤(不仅包含url,还有callback函数、headers等信息),导致的结果就是会降低爬⾍速度、⽽且会占⽤Redis⼤量的存储空间。当然我们可以重写⽅法实现调度url或者⽤户ID。
【策略⼆】 这是对策略的⼀种优化改进:在Master端跑⼀个程序去⽣成任务(Request/url/ID)。Master端负责的是⽣产任务,并把任务去重、加⼊到待爬队列。Slaver只管从Master端拿任务去爬。 优点: 将⽣成任务和抓取数据分开,分⼯明确,减少了Master和Slaver之间的数据交流;Master端⽣成任务还有⼀个好处就是:可以很⽅便地重写判重策略(当数据量⼤时优化判重的性能和速度还是很重要的)。 缺点:像QQ或者新浪微博这种⽹站,发送⼀个请求,返回的内容⾥⾯可能包含⼏⼗个待爬的⽤户ID,即⼏⼗个新爬⾍任务。但有些⽹站⼀个请求只能得到⼀两个新任务,并且返回的内容⾥也包含爬⾍要抓取的⽬标信息,如果将⽣成任务和抓取任务分开反⽽会降低爬⾍抓取效率。毕竟带宽也是爬⾍的⼀个瓶颈问题,我们要秉着发送尽量少的请求为原则,同时也是为了减轻⽹站服务器的压⼒,要做⼀只有道德的Crawler。所以,视情况⽽定。
【策略三】 Master中只有⼀个集合,它只有查询的作⽤。Slaver在遇到新任务时询问Master此任务是否已爬,如果未爬则加⼊Slaver⾃⼰的待爬队列中,Master把此任务记为已爬。它和策略⼀⽐较像,但明显⽐策略⼀简单。策略⼀的简单是因为有scrapy-redis实现了scheduler中间件,它并不适⽤于⾮scrapy框架的爬⾍。 优点: 实现简单,⾮scrapy框架的爬⾍也适⽤。Master端压⼒⽐较⼩,Master与Slaver的数据交流也不⼤。 缺点: “健壮性”不够,需要另外定时保存待爬队列以实现“断点续爬”功能。各Slaver的待爬任务不通⽤。
结语: 如果把Slaver⽐作⼯⼈,把Master⽐作⼯头。策略⼀就是⼯⼈遇到新任务都上报给⼯头,需要⼲活的时候就去⼯头那⾥领任务;策略⼆就是⼯头去找新任务,⼯⼈只管从⼯头那⾥领任务⼲活;策略三就是⼯⼈遇到新任务时询问⼯头此任务是否有⼈做了,没有的话⼯⼈就将此任务加到⾃⼰的“⾏程表”。
因篇幅问题不能全部显示,请点此查看更多更全内容