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數據。