scrapy-redis模块
scrapy-redis是为了实现scrapy的分布式爬取而提供了一个python库,通过更换scrapy的内置组件,将爬取请求队列和item数据放入第三方的redis数据库中,由此可以有多个scrapy进程从redis中读取request数据和写入items数据,实现分布式处理。
redis主要工作:
储存request请求,形成一个队列供不同的多个scrapy进行消费。scrapy-redis提供了三种队列,可自由配置。
PriorityQueue(优先队列:默认):通过redis的有序集合实现,同时集合可以自动对request去重
FifoQueue和LifoQueue:通过List实现
储存item数据
对request进行去重,需要使用一个集合的数据结构来实现快速的去重。
安装scrapy-redis
pip install scrapy-redis即可安装,官方要求python和redis版本如下:
Python 2.7, 3.4 or 3.5
Redis >= 2.8
Scrapy >= 1.1
redis-py >= 2.10
配置scrapy-redis
scrapy-redis是在原scrapy的基础上,通过替换部分scrapy组件来实现,这些组件包括。
Scheduler:使用redis作为request的调度队列,需要更换schedule类,配置文件中配置即可
DuplicationFilter:通过redis的set对request进行去重,去重的指纹采用method+url+body+header的信息,通过hash函数生成hash值存入redis的一个set中,使用时在配置文件中直接配置即可
ItemPipeline:使用一个pipeline将爬取的数据储存到redis服务中,配置文件中添加该类即可
Base Spiders:spider对象是一个爬虫的核心对象,该类的定义由我们自己实现,在原来scarapy框架中通过继承内置Spider类来获得了公用的功能。这里我们需要使用scrapy-redis提供的RedisSpider类作为父类,继承与redis进行连接通信的方法,而不用我们手动连接redis。
更换上述的组件的方式通过配置文件即可完成,只有spider类的定义需要我们更改继承的父类即可。
配置文件
作者给出可添加的配置文件的全部内容,需要时进行添加配置即可。githu地址https://github.com/rmax/scrapy-redis
#Enables scheduling storing requests queue in redis.
配置后使用redis中队列实现了request的调度。
SCHEDULER= "scrapy_redis.scheduler.Scheduler"
#过滤重复request方式,避免重复爬取
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#默认使用pickle进行序列化,可以指定为“json”或 “msgpack”#SCHEDULER_SERIALIZER = "json" # "msgpack" json和msgpack均可调用dump和loads方法
SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"
#不会清空request队列,阻塞等待downloader获取request爬取#SCHEDULER_PERSIST = True
#Schedule requests 默认使用PriorityQueue (优先队列)
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
#其他可选的有#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'
#Max idle(闲置) time 分布式情况下最大的闲置时间,超过该时间该spider没有获取数据则可能已经关闭.#queue class 是 SpiderQueue or SpiderStack 时才生效#这可能会让你的爬虫刚开始启动时阻塞的,因为这个queue是空的#SCHEDULER_IDLE_BEFORE_CLOSE = 10
#Store scraped item in redis for post-processing.#处理item的类,该类会将item保存到redis的中,并使用指定的序列化方式,和REDIS_ITEMS_KEY指定的key储存
ITEM_PIPELINES ={'scrapy_redis.pipelines.RedisPipeline': 300}#item信息被序列化后储存在该key中,默认key为
REDIS_ITEMS_KEY = '%(spider)s:items'
#将item对象进行序列化的方式,默认为 ScrapyJSONEncoder. 可以指定其他序列化方式,指定一个序列化函数即可,例如下面json.dump#REDIS_ITEMS_SERIALIZER = 'json.dumps'
#Specify the host and port to use when connecting to Redis (optional).#REDIS_HOST = 'localhost'#REDIS_PORT = 6379#设置后优先选择url的方式连接#REDIS_URL = 'redis://user:pass@hostname:9001'
#Custom redis client parameters (i.e.: socket timeout, etc.)#REDIS_PARAMS = {}#Use custom redis client class.#REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient'
#多个start_url时是否储存为一个set,方便去重#REDIS_START_URLS_AS_SET = False
#starturl储存在redis中的key的名字#REDIS_START_URLS_KEY = '%(name)s:start_urls'
#Use other encoding than utf-8 for redis.#REDIS_ENCODING = 'latin1'
以上是全部的配置文件的内容,通常不用进行全部的配置,添加下面的配置即可
#更换scheduler组件
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue' # 如果不指定使用优先队列
#指定对request去重所使用的类,该类继承自scrapy中的饿BaseDupeFilter,重写了部分方法
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#更改原配置文件中的ITEM_PIPELINES
ITEM_PIPELINES ={'scrapy_redis.pipelines.RedisPipeline': 300, #该pipeline是item数据写入redis,也可以指定其他pipeline
}#在redis中保存item数据的key的名字
REDIS_ITEMS_KEY = '%(spider)s:items'REDIS_HOST= '192.168.236.100'REDIS_PORT= 6379
#start_url储存在redis中的key的名字, 该值在会绑定在spider对象的redis_key属性上
REDIS_START_URLS_KEY = '%(name)s:start_urls'
spider
spider需要从scrapy-redis模块中继承spider类,scrapy中有两个spider类,分别为Spider和CrawlSpider类,scrapy-redis通过Mixin的方式,将RedisMixin类混入原来的两个spider类中,得到了RedisSpider和RedisCrawlSpider,使用时将原来的spider类对应更换为新的RedisSpider或RedisCrawlSpider类即可
from scrapy.linkextractors importLinkExtractorfrom scrapy.spiders import Rule #CrawlSpider
from scrapy.http.response.html importHtmlResponsefrom scrapy_redis.spiders importRedisCrawlSpiderclass ReviewSpider(RedisCrawlSpider): #使用RedisCrawlSpider替换原CrawlSpider类
name = 'name'allowed_domains= ['domain.com']#如果指定了start_urls,会将该start_urls存如redis对应的指定的key中
#如果没有指定,scrapy将阻塞等待redis的start_urls对应的key中被添加url来开始爬取
#start_urls = []
redis_key = "reviews:start_url" #start_url对应redis中的key,没有指定使用配置文件中的REDIS_START_URLS_KEY = '%(name)s:start_urls'配置的值作为key
rules=(
Rule(LinkExtractor(allow=r'Item'), callback='parse_item', follow=True),
)defparse_item(self, response: HtmlResponse):pass
#return items
运行scrapy
更改以上配置后,运行该scrapy爬虫,由于start_url中没有起始的url,程序将会阻塞等待提供起始url,scrapy时从redis中获取url,且key为上述spider中定义的redis_key属性的内容,即"reviews:start_url",所以只需要手动向该key写入一个start_url数据即可开始爬取。该key的类型默认为一个List,(除非配置文件中有一个选项指定该key的为一个set)。
进入redis客户端,执行lpush reviews:start_url 添加一个初始url即可开始爬取。
运行后查看redis中的数据,增加了三个key信息。
review:dupefilter:类型为set,存放已爬取request指纹信息,保存的是每个request经过hash函数计算后的结果
review:items:类型为list, 存放经过序列化后的item数据,默认使用json.dumps的序列化方式。
review;start_url:类型为list,起始的url数据。