python分布式爬蟲框架 --- scrapy-redis


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM