關於Scrapy工作流程回顧
Scrapy單機架構
上圖的架構其實就是一種單機架構,只在本機維護一個爬取隊列,Scheduler進行調度,而要實現多態服務器共同爬取數據關鍵就是共享爬取隊列。
分布式架構
將上圖進行再次更改
這里重要的就是我的隊列通過什么維護?
-
關於爬取隊列我們自然想到的是基於內存存儲的Redis。它支持多種數據結構,如:列表、集合、有序集合等,存取的操作也非常簡單。
-
Redis支持的這幾種數據結構,在存儲中都有各自優點:
-
列表(list)有lpush()、lpop()、rpush()、rpop()方法,可以實現先進先出的隊列和先進后出的棧式爬蟲隊列。
-
集合(set)的元素是無序且不重復的,這樣我們可以非常方便的實現隨機且不重復的爬取隊列。
-
有序集合有分數表示,而Scrapy的Request也有優先級的控制,我們可以用它來實現帶優先級調度的隊列。
如何去重?
這里借助redis的集合,redis提供集合數據結構,在redis集合中存儲每個request的指紋
在向request隊列中加入Request前先驗證這個Request的指紋是否已經加入集合中。如果已經存在則不添加到request隊列中,如果不存在,則將request加入到隊列並將指紋加入集合
如何防止中斷?如果某個slave因為特殊原因宕機,如何解決?
-
在Scrapy中,爬蟲運行時的Request隊列放在內存中。爬蟲運行中斷后,這個隊列的空間就會被釋放,導致爬取不能繼續。
-
要做到中斷后繼續爬取,我們可以將隊列中的Request保存起來,下次爬取直接讀取保存的數據既可繼續上一次爬取的隊列。
-
在Scrapy中制定一個爬取隊列的存儲路徑即可,這個路徑使用
JOB_DIR
變量來標識,命令如下:scrapy crawl spider -s JOB_DIR=crawls/spider
-
更多詳細使用請詳見官方文檔:http://doc.scrapy.org/en/latest/topics/jobs.html
-
在Scrapy中,我們實際是把爬取隊列保存到本地,第二次爬取直接讀取並恢復隊列既可。
-
在分布式框架中就不用擔心這個問題了,因為爬取隊列本身就是用數據庫存儲的,中斷后再啟動就會接着上次中斷的地方繼續爬取。
-
當Redis的隊列為空時,爬蟲會重新爬取;當隊列不為空時,爬蟲便會接着上次中斷支處繼續爬取。
如何實現上述這種架構?
這里有一個scrapy-redis的庫,為我們提供了上述的這些功能,scrapy-redis改寫了Scrapy的調度器,隊列等組件,利用他可以方便的實現Scrapy分布式架構
關於scrapy-redis的地址:https://github.com/rmax/scrapy-redis
搭建分布式爬蟲
考官網地址:https://scrapy-redis.readthedocs.io/en/stable/
前提是要安裝scrapy_redis模塊:pip install scrapy_redis
這里的爬蟲代碼是用的之前寫過的爬取知乎用戶信息的爬蟲
修改該settings中的配置信息:(一般設置標紅出即可)
替換scrapy調度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
添加去重的class
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
添加pipeline
如果添加這行配置,每次爬取的數據也都會入到redis數據庫中,所以一般這里不做這個配置
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}
共享的爬取隊列,這里用需要redis的連接信息
這里的user:pass表示用戶名和密碼,如果沒有則為空就可以
REDIS_URL = 'redis://password@host:6379'
設置為為True則不會清空redis里的dupefilter和requests隊列
這樣設置后指紋和請求隊列則會一直保存在redis數據庫中,默認為False,一般不進行設置
SCHEDULER_PERSIST = True
設置重啟爬蟲時是否清空爬取隊列
這樣每次重啟爬蟲都會清空指紋和請求隊列,默認設置為False不清空,在單機爬取時此配置比較方便,分布式爬取一般不用此配置。
SCHEDULER_FLUSH_ON_START=True
分布式
將上述更改后的代碼拷貝的各個服務器,當然關於數據庫這里可以在每個服務器上都安裝數據,也可以共用一個數據,我這里方面是連接的同一個mongodb數據庫,當然各個服務器上也不能忘記:
所有的服務器都要安裝scrapy,scrapy_redis,pymongo
這樣運行各個爬蟲程序啟動后,在redis數據庫就可以看到如下內容,dupefilter是指紋隊列,requests是請求隊列