安裝scrapy-redis
pip install scrapy-redis
從GitHub 上拷貝源碼:
clone github scrapy-redis源碼文件 git clone https://github.com/rolando/scrapy-redis.git
scrapy-redis的工作流程
Scrapy_redis之domz 例子分析
1.domz爬蟲:
2.配置中:
3.執行domz的爬蟲,會發現redis中多了一下三個鍵
redispipeline中僅僅實現了item數據存儲到redis的過程,我們可以新建一個pipeline(或者修改默認的ExamplePipeline),可以讓數據存儲到任意地方。
scrapy-redis 的源碼分析
1.Scrapy_redis之RedisPipeline
2.Scrapy_redis之RFPDupeFilter
3.Scrapy_redis之Scheduler
domz相比於之前的spider多了持久化和request去重的功能,setting中的配置都是可以自己設定的,
意味着我們的可以重寫去重和調度器的方法,包括是否要把數據存儲到redis(pipeline)
1.Scrapy_redis之RedisSpider
2. Scrapy_redis之RedisCrawlSpider
scrapy-redis 配置:
在爬蟲項目的settings.py文件中,可以做一下配置
# ####################### redis配置文件 ####################### REDIS_HOST = '192.168.11.81' # 主機名 REDIS_PORT = 6379 # 端口 # REDIS_URL = 'redis://user:pass@hostname:9001' # 連接URL(優先於以上配置) # REDIS_PARAMS = {} # Redis連接參數 默認:REDIS_PARAMS = {'socket_timeout': 30,'socket_connect_timeout': 30,'retry_on_timeout': True,'encoding': REDIS_ENCODING,}) # REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定連接Redis的Python模塊 默認:redis.StrictRedis REDIS_ENCODING = "utf-8" # redis編碼類型 默認:'utf-8' # df DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 也可以自定義自己的去重規則 from scrapy_redis.scheduler import Scheduler SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 調度器 from scrapy_redis.queue import PriorityQueue from scrapy_redis import picklecompat SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue' # 默認使用優先級隊列(默認),其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表) SCHEDULER_QUEUE_KEY = '%(spider)s:requests' # 調度器中請求存放在redis中的key SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat" # 對保存到redis中的數據進行序列化,默認使用pickle SCHEDULER_PERSIST = True # 是否在關閉時候保留原來的調度器和去重記錄,True=保留,False=清空 SCHEDULER_FLUSH_ON_START = False # 是否在開始之前清空 調度器和去重記錄,True=清空,False=不清空 SCHEDULER_IDLE_BEFORE_CLOSE = 10 # 去調度器中獲取數據時,如果為空,最多等待時間(最后沒數據,未獲取到)。 SCHEDULER_DUPEFILTER_KEY = '%(spider)s:dupefilter' # 去重規則,在redis中保存時對應的key SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter' # 去重規則對應處理的類 from scrapy_redis.pipelines import RedisPipeline ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 300, } REDIS_ITEMS_KEY = '%(spider)s:items' REDIS_ITEMS_SERIALIZER = 'json.dumps'
Crontab爬蟲定時執行
Scrapy-redis 中的知識總結
request對象什么時候入隊
-
dont_filter = True ,構造請求的時候,把dont_filter置為True,該url會被反復抓取(url地址對應的內容會更新的情況)
-
一個全新的url地址被抓到的時候,構造request請求
-
url地址在start_urls中的時候,會入隊,不管之前是否請求過
-
構造start_url地址的請求時候,dont_filter = True
-
def enqueue_request(self, request):
if not request.dont_filter and self.df.request_seen(request):
# dont_filter=False Ture True request指紋已經存在 #不會入隊
# dont_filter=False Ture False request指紋已經存在 全新的url #會入隊
# dont_filter=Ture False #會入隊
self.df.log(request, self.spider)
return False
self.queue.push(request) #入隊
return True
scrapy_redis去重方法
-
使用sha1加密request得到指紋
-
把指紋存在redis的集合中
-
下一次新來一個request,同樣的方式生成指紋,判斷指紋是否存在reids的集合中
生成指紋
fp = hashlib.sha1()
fp.update(to_bytes(request.method)) #請求方法
fp.update(to_bytes(canonicalize_url(request.url))) #url
fp.update(request.body or b'') #請求體
return fp.hexdigest()
判斷數據是否存在redis的集合中,不存在插入
added = self.server.sadd(self.key, fp) return added != 0