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类,配置文件中配置即可
- Duplication Filter:通过redis的set对request进行去重,去重的指纹采用method+url+body+header的信息,通过hash函数生成hash值存入redis的一个set中,使用时在配置文件中直接配置即可
- Item Pipeline:使用一个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 import LinkExtractor from scrapy.spiders import Rule # CrawlSpider from scrapy.http.response.html import HtmlResponse from scrapy_redis.spiders import RedisCrawlSpider class 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), ) def parse_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 <start_url>
添加一个初始url即可开始爬取。
运行后查看redis中的数据,增加了三个key信息。
- review:dupefilter:类型为set,存放已爬取request指纹信息,保存的是每个request经过hash函数计算后的结果
- review:items:类型为list, 存放经过序列化后的item数据,默认使用json.dumps的序列化方式。
- review;start_url:类型为list,起始的url数据。