scrapy_redis
Scrapy和scrapy-redis的区别:
Scrapy是一个普通的爬虫框架,但不支持分布式,scrapy-redis是为了更方便地实现Scrapy分布爬取,而提供了一些以redis为基础的组件(仅有组件)。
安装:pip install scrapy-redis
scrapy-redis提供了下面四种组件,(这四种组件意味着这四个模块都要做相应的修改)
1.Scheduler
2.Duplication Filter
3.Item Pipeline
4.Base Spider
Scheduler:Scrapy改造了python本来的collection.deque(双向队列)形成了自己的Scrapy.
但是Scrapy多个spider不能共享待爬取队列Scrapy queue,即Scrapy本身不支持爬虫分布式,scrapy-redis的解决是把这个Scrapy queue换成redis数据库(也只redis队列),
从同一个redis-server存放要爬取的request,便能让多个spider去同一个数据库里读取。
Scrapy中跟'待爬队列'直接相关的就是调度器,它负责对新的request进行入列操作(加入Scrapy queue),去除下一个要爬取的request(从Scrapy queue中取出)等操作。它把待爬队列
按照优先级建立了一个字典结构,如{优先级0:队列0,优先级1:队列2},然后根据中request中的优先级,来确定该入哪个队列,出列时则按照优先级较小的优先出列,为了管理这个比较高级的队
列字典,Scheduler需要提供一系列的方法。但是原来的Scheduler已经无法使用,所以使用Scrapy-redis的scheduler组件。
Duplication Filter:
Scrapy中用集合实现这个request去重功能,Scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合对比,如果该指纹存在于集合中,说明这个request发
送过了,如果没有则继续操作,这个核心的判断功能是这样的:
在scrapy-redis中去重是由Duplication Filter组件来实现的,它通过redis的set不能重复的特性,巧妙的实现了Duplication Filter去重。scrapy-redis调度器从引擎接受
request,将request的指纹存入redis的set检查是否重复,并将不重复的request push写入redis的request queue。
引擎请求request(spider发出的)时,调度器从redis的request queue队列里根据优先级pop出一个request返回给引擎,引擎将此request发给spider处理。
Item Pipeline:
引擎将(Spider返回的)爬取到的Item给Item Pipeline,scrapy-redis的Item Pipeline将取到的Item存入redis的items queue。
修改过的Item Pipeline可以很方便的根据key 从items queue提取item,从而实现items processes集群。
Base spider:
不在使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url的类。
当我们生成一个Spider继承RodisSpider时,调用setup_redis函数,这个函数会连接reids数据库,然后会设置singles(信号):
1.一个是当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,并且抛出DontCloseSpider异常。
2.一个是当抓到一个item时的signal,会调用item_scraped函数,获取下一个request。
Scrapy-Redis分步式策略:
Master端(核心服务器):例如在windows,搭建一个Redis数据库,不负责爬取,只负责url指纹判重,Request的分配,以及数据库的存储。
Slaver端(爬虫程序执行端):负责执行爬虫程序,运行程序过程中提交新的Request给Master。
1.首先Slaver端从Master端拿任务(Request,url)进行数据抓取,Slaver抓取数据的同时,产生新任务的Request便提交给Master处理。
2.Master端只有一个redis数据库,负责将未处理的Request去重和任务分配,将处理后的Request加入待爬队列,并且存储爬取的数据。
Scrapy-Redis默认使用的就是这种策略,我们实现起来很简单,因为任务调度等工作Scrapy-Redis都已经帮我们做好了,我们只需要继承RedisSpider,指定redis_key就行了。
缺点是Scrapy-Redis调度的任务是Request对象,里面信息比较大(不仅包含url,还有callback函数,headers等信息),可是导致的结果就是会降低爬虫速度,而且
会占用大量的存储空间,所以如果要保证效率,那么就需要一定的硬件水平。
修改配置文件redis.conf
Master端redis.conf里注释bind 127.0.0.1,slave端才能远程连接到Master端的redis的数据库
sudo redis-cli -h ip地址... -h指定一个目标终端,在linux