pip3 install scrapy-redis
Scrapy-redis提供了四種組件(components):
(四種組件意味著這四個(gè)模塊都要做相應(yīng)的修改)
- Scheduler
Scrapy中跟“待爬隊(duì)列”直接相關(guān)的就是調(diào)度器Scheduler,它負(fù)責(zé)對(duì)新的request進(jìn)行入列操作(加入Scrapy queue),取出下一個(gè)要爬取的request(從Scrapy queue中取出)等操作。它把待爬隊(duì)列按照優(yōu)先級(jí)建立了一個(gè)字典結(jié)構(gòu)。
- Duplication Filter
Scrapy中用集合實(shí)現(xiàn)這個(gè)request去重功能,Scrapy中把已經(jīng)發(fā)送的request指紋放入到一個(gè)集合中,把下一個(gè)request的指紋拿到集合中比對(duì),如果該指紋存在于集合中,說明這個(gè)request發(fā)送過了,如果沒有則繼續(xù)操作。
在scrapy-redis中去重是由Duplication Filter組件來實(shí)現(xiàn)的,它通過redis的set 不重復(fù)的特性,巧妙的實(shí)現(xiàn)了Duplication Filter去重。scrapy-redis調(diào)度器從引擎接受request,將request的指紋存?redis的set檢查是否重復(fù),并將不重復(fù)的request push寫?redis的 request queue。
引擎請(qǐng)求request(Spider發(fā)出的)時(shí),調(diào)度器從redis的request queue隊(duì)列?里根據(jù)優(yōu)先級(jí)pop 出?個(gè)request 返回給引擎,引擎將此request發(fā)給spider處理。
- Item Pipeline
引擎將(Spider返回的)爬取到的Item給Item Pipeline,scrapy-redis 的Item Pipeline將爬取到的 Item 存?redis的 items queue。
修改過Item Pipeline可以很方便的根據(jù) key 從 items queue 提取item,從?實(shí)現(xiàn) items processes集群。
- Base Spider
不在使用scrapy原有的Spider類,重寫的RedisSpider繼承了Spider和RedisMixin這兩個(gè)類,RedisMixin是用來從redis讀取url的類。
當(dāng)我們生成一個(gè)Spider繼承RedisSpider時(shí),調(diào)用setup_redis函數(shù),這個(gè)函數(shù)會(huì)去連接redis數(shù)據(jù)庫,然后會(huì)設(shè)置signals(信號(hào)):
一個(gè)是當(dāng)spider空閑時(shí)候的signal,會(huì)調(diào)用spider_idle函數(shù),這個(gè)函數(shù)調(diào)用schedule_next_request函數(shù),保證spider是一直活著的狀態(tài),并且拋出DontCloseSpider異常。
一個(gè)是當(dāng)抓到一個(gè)item時(shí)的signal,會(huì)調(diào)用item_scraped函數(shù),這個(gè)函數(shù)會(huì)調(diào)用schedule_next_request函數(shù),獲取下一個(gè)request。
Scrapy_redis式工作流程

修改設(shè)置文件
(1)設(shè)置去重組件,使用的是scrapy_redis的去重組件,而不再使用scrapy框架自己的去重組件了
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
(2)設(shè)置調(diào)度器,使用的是scrapy_redis重寫的調(diào)度器,而不再使用scrapy框架自帶的調(diào)度器了
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
(3)可以實(shí)現(xiàn)斷點(diǎn)爬?。ㄕ?qǐng)求的記錄不會(huì)丟失,會(huì)存儲(chǔ)在redis數(shù)據(jù)庫中,不會(huì)清除redis的任務(wù)隊(duì)列)
SCHEDULER_PERSIST = True
(4)設(shè)置任務(wù)隊(duì)列的模式(三選一)
SpiderPriorityQueue是scrapy_redis默認(rèn)使用的隊(duì)列模式
(有自己的優(yōu)先級(jí))
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
使用了隊(duì)列的形式,任務(wù)先進(jìn)先出
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
采用了棧的形式,任務(wù)先進(jìn)后出
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"
(5)實(shí)現(xiàn)這個(gè)管道,可以將爬蟲端獲取的item數(shù)據(jù),統(tǒng)一保存在redis數(shù)據(jù)庫中
'scrapy_redis.pipelines.RedisPipeline': 400,
(6)指定要存儲(chǔ)的redis數(shù)據(jù)庫的主機(jī)ip
REDIS_HOST = '127.0.0.1'
指定redis數(shù)據(jù)庫主機(jī)的端口
REDIS_PORT = 6379
"xcfCrawlSpider:requests":存儲(chǔ)的是請(qǐng)求的request對(duì)象
"xcfCrawlSpider:items":存儲(chǔ)的爬蟲端獲取的items數(shù)據(jù)
"xcfCrawlSpider:dupefilter":存儲(chǔ)的指紋(為了實(shí)現(xiàn)去重)
127.0.0.1:6379> type xcfCrawlSpider:requests
zset
127.0.0.1:6379> type xcfCrawlSpider:items
list
127.0.0.1:6379> type xcfCrawlSpider:dupefilter
set
第一種情況:只設(shè)置settings.py文件,并沒有實(shí)現(xiàn)分布式,知識(shí)使用了sctapy_redis的數(shù)據(jù)存儲(chǔ)和去重功能
-
第二種情況:實(shí)現(xiàn)通用爬蟲的分布式爬蟲
from scrapy_redis.spiders import RedisCrawlSpider #繼承制:RedisCrawlSpider class MyCrawler(RedisCrawlSpider): """Spider that reads urls from redis queue (myspider:start_urls).""" name = 'mycrawler_redis' allowed_domains = ['dmoz.org'] #缺少了start_url,多了redis_key:根據(jù)redis_key從redis #數(shù)據(jù)庫中獲取任務(wù) redis_key = 'mycrawler:start_urls' 啟動(dòng)爬蟲:scrapy crawl 爬蟲名稱
現(xiàn)象:爬蟲處于等待狀態(tài)
需要設(shè)置起始任務(wù):
lpush mycrawler:start_urls 目標(biāo)url
-
第三中情況:實(shí)現(xiàn)scrpy.spider爬蟲的分布式爬蟲
from scrapy_redis.spiders import RedisSpider #繼承制:RedisSpider class MyCrawler(RedisSpider): """Spider that reads urls from redis queue (myspider:start_urls).""" name = 'mycrawler_redis' allowed_domains = ['dmoz.org'] #缺少了start_url,多了redis_key:根據(jù)redis_key從redis #數(shù)據(jù)庫中獲取任務(wù) redis_key = 'mycrawler:start_urls'啟動(dòng)爬蟲:scrapy crawl 爬蟲名稱
現(xiàn)象:爬蟲處于等待狀態(tài)
需要設(shè)置起始任務(wù):
lpush mycrawler:start_urls 目標(biāo)url
僅為個(gè)人學(xué)習(xí)小結(jié),若有錯(cuò)處,歡迎指正~