scrapy-redis 官方github地址
1笆呆, scrapy-redis的簡(jiǎn)單理解
Scrapy 是一個(gè)通用的爬蟲框架,但是不支持分布式,Scrapy-redis是為了更方便地實(shí)現(xiàn)Scrapy分布式爬取,而提供了一些以redis為基礎(chǔ)的組件(僅有組件)踩叭。
安裝:pip install scrapy-redis
Scrapy-redis提供了下面四種組件(components):(四種組件意味著這四個(gè)模塊都要做相應(yīng)的修改)
- Scheduler(隊(duì)列)
- Duplication Filter (去重)
- Item Pipeline(將Item存儲(chǔ)在redis中以實(shí)現(xiàn)分布式處理)
- Base Spider
Scheduler:
Scrapy改造了python本來的collection.deque(雙向隊(duì)列)形成了自己的Scrapy queue(https://github.com/scrapy/queuelib/blob/master/queuelib/queue.py)),但是Scrapy多個(gè)spider不能共享待爬取隊(duì)列Scrapy queue翠胰, 即Scrapy本身不支持爬蟲分布式,scrapy-redis 的解決是把這個(gè)Scrapy queue換成redis數(shù)據(jù)庫(也是指redis隊(duì)列)自脯,從同一個(gè)redis-server存放要爬取的request之景,便能讓多個(gè)spider去同一個(gè)數(shù)據(jù)庫里讀取。
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),比如:
{
優(yōu)先級(jí)0 : 隊(duì)列0
優(yōu)先級(jí)1 : 隊(duì)列1
優(yōu)先級(jí)2 : 隊(duì)列2
}
然后根據(jù)request中的優(yōu)先級(jí)轻纪,來決定該入哪個(gè)隊(duì)列油额,出列時(shí)則按優(yōu)先級(jí)較小的優(yōu)先出列。為了管理這個(gè)比較高級(jí)的隊(duì)列字典刻帚,Scheduler需要提供一系列的方法潦嘶。但是原來的Scheduler已經(jīng)無法使用,所以使用Scrapy-redis的scheduler組件崇众。
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è)有四臺(tái)電腦:Windows 10泊柬、Mac OS X、Ubuntu 16.04诈火、CentOS 7.2兽赁,任意一臺(tái)電腦都可以作為 Master端 或 Slaver端,比如:
Master端(核心服務(wù)器) :使用 Windows 10柄瑰,搭建一個(gè)Redis數(shù)據(jù)庫闸氮,不負(fù)責(zé)爬取,只負(fù)責(zé)url指紋判重教沾、Request的分配蒲跨,以及數(shù)據(jù)的存儲(chǔ)
Slaver端(爬蟲程序執(zhí)行端) :使用 Mac OS X 、Ubuntu 16.04授翻、CentOS 7.2或悲,負(fù)責(zé)執(zhí)行爬蟲程序,運(yùn)行過程中提交新的Request給Master
首先Slaver端從Master端拿任務(wù)(Request堪唐、url)進(jìn)行數(shù)據(jù)抓取巡语,Slaver抓取數(shù)據(jù)的同時(shí),產(chǎn)生新任務(wù)的Request便提交給 Master 處理淮菠;
Master端只有一個(gè)Redis數(shù)據(jù)庫男公,負(fù)責(zé)將未處理的Request去重和任務(wù)分配,將處理后的Request加入待爬隊(duì)列合陵,并且存儲(chǔ)爬取的數(shù)據(jù)枢赔。
核心參數(shù)
settings.py
# ===========================================================================
#啟用Redis調(diào)度存儲(chǔ)請(qǐng)求隊(duì)列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#確保所有的爬蟲通過Redis去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#默認(rèn)請(qǐng)求序列化使用的是pickle 但是我們可以更改為其他類似的。PS:這玩意兒2.X的可以用拥知。3.X的不能用
#SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"
#不清除Redis隊(duì)列踏拜、這樣可以暫停/恢復(fù) 爬取
#SCHEDULER_PERSIST = True
#使用優(yōu)先級(jí)調(diào)度請(qǐng)求隊(duì)列 (默認(rèn)使用)
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
#可選用的其它隊(duì)列
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'
#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'
#最大空閑時(shí)間防止分布式爬蟲因?yàn)榈却P(guān)閉
#這只有當(dāng)上面設(shè)置的隊(duì)列類是SpiderQueue或SpiderStack時(shí)才有效
#并且當(dāng)您的蜘蛛首次啟動(dòng)時(shí),也可能會(huì)阻止同一時(shí)間啟動(dòng)(由于隊(duì)列為空)
#SCHEDULER_IDLE_BEFORE_CLOSE = 10
#將清除的項(xiàng)目在redis進(jìn)行處理
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}
#序列化項(xiàng)目管道作為redis Key存儲(chǔ)
#REDIS_ITEMS_KEY = '%(spider)s:items'
#默認(rèn)使用ScrapyJSONEncoder進(jìn)行項(xiàng)目序列化
#You can use any importable path to a callable object.
#REDIS_ITEMS_SERIALIZER = 'json.dumps'
#指定連接到redis時(shí)使用的端口和地址(可選)
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
#指定用于連接redis的URL(可選)
#如果設(shè)置此項(xiàng)低剔,則此項(xiàng)優(yōu)先級(jí)高于設(shè)置的REDIS_HOST 和 REDIS_PORT
#REDIS_URL = 'redis://user:pass@hostname:9001'
#自定義的redis參數(shù)(連接超時(shí)之類的)
#REDIS_PARAMS = {}
#自定義redis客戶端類
#REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient'
#如果為True速梗,則使用redis的'spop'進(jìn)行操作。
#如果需要避免起始網(wǎng)址列表出現(xiàn)重復(fù)襟齿,這個(gè)選項(xiàng)非常有用姻锁。開啟此選項(xiàng)urls必須通過sadd添加,否則會(huì)出現(xiàn)類型錯(cuò)誤猜欺。
#REDIS_START_URLS_AS_SET = False
#RedisSpider和RedisCrawlSpider默認(rèn) start_usls 鍵
#REDIS_START_URLS_KEY = '%(name)s:start_urls'
#設(shè)置redis使用utf-8之外的編碼
#REDIS_ENCODING = 'latin1'
spider
from scrapy_redis.spiders import RedisCrawlSpider
class Spider(RedisCrawlSpider):#繼承scrapy-redis中定義好的類
pass
注釋:
- 當(dāng)使用分布式爬蟲爬取數(shù)據(jù)時(shí)屋摔,要保證redis數(shù)據(jù)庫例遠(yuǎn)程之間可以連接
- Master端和Slaver端要使用統(tǒng)一的redis數(shù)據(jù)庫保證項(xiàng)目的連接使用
- 在Linux中配置Master端,修改配置文件 redis.conf替梨,打開redis.conf配置文件钓试,示例:linux系統(tǒng):
sudo vi /etc/redis/redis.conf
,Master端redis.conf
里注釋bind 127.0.0.1
,Slave端才能遠(yuǎn)程連接到Master端的Redis數(shù)據(jù)庫副瀑。如果要把當(dāng)前電腦當(dāng)成Master端把bind 127.0.0.1
注釋掉弓熏,如果是Slaver端可以不修改
redis.conf
中daemonize
配置
daemonize no
表示Redis默認(rèn)不作為守護(hù)進(jìn)程運(yùn)行,即在 運(yùn)行redis-server /etc/redis/redis.conf
時(shí)糠睡,將顯示Redis 啟動(dòng)提示畫面挽鞠;daemonize yes
則默認(rèn)后臺(tái)運(yùn)行,不必重新啟動(dòng)新的終端窗口執(zhí)行其他命令狈孔,看個(gè)人喜好和實(shí)際需
- Linux中啟動(dòng)redis服務(wù)
推薦指定配置文件啟動(dòng)
sudo redis-server /etc/redis/redis.conf
或者sudo service redis start
- Linux中停止redis服務(wù)
sudo kill -9 redis的進(jìn)程id
或者sudo service redis stop
- Linux中重啟redis服務(wù)
sudo service redis restart
當(dāng)配置文件重新配置后信认,一般會(huì)重啟服務(wù)器這樣配置才生效
- 保證存儲(chǔ)數(shù)據(jù)庫之間的連接,當(dāng)master和slaver端要同時(shí)存入master端的mysql數(shù)據(jù)庫均抽,要保證slaver端是否可以連接master端的數(shù)據(jù)庫
- 在Ubuntu16.04下安裝mysql:https://blog.csdn.net/xiangwanpeng/article/details/54562362