問題描述
預設RedisSpider
在啟動時,首先會讀取redis
中的spidername:start_urls
,如果有值則根據url
構建request
物件。
現在的要求是,根據特定關鍵詞采集。
例如:目標站點有一個介面,根據post請求引數來返回結果。
那麼,在這種情況下,構建request
主要的變換就是請求體(body),API介面是不變的。
對於原來通過url
構建request
的策略就不再適用了。
所以,此時我們需要對相應的方法進行重寫。
重寫方法
爬蟲類需要繼承至scrapy_redis.spiders.RedisSpider
start_requests
我需要從資料庫拿到關鍵詞資料,然後用關鍵詞構建請求。
此時,我們將關鍵詞看作start_url
,將關鍵詞push
到redis
中
首先,寫一個將單個關鍵詞push
到redis
的方法
push_data_to_redis
def push_data_to_redis(self, data):
"""將資料push到redis"""
# 序列化,data可能是字典
data = pickle.dumps(data)
use_set = self.settings.getbool('REDIS_START_URLS_AS_SET', defaults.START_URLS_AS_SET)
self.server.spush(self.redis_key, data) if use_set else self.server.lpush(self.redis_key, data)
self.redis_key
如果沒有做任何宣告,則預設為 spidername:start_urls
接著重寫start_request
def start_requests(self):
if self.isproducer():
# get_keywords 從資料庫讀關鍵詞的方法
items = self.get_keywords()
for item in items:
self.push_data_to_redis(item)
return super(DoubanBookMetaSpider, self).start_requests()
上述程式碼中有一個self.isproducer
,此方法用於檢測當前程式是不是生產者,即向redis
提供關鍵詞
isproducer
# (...)
def __init__(self, *args, **kwargs):
self.is_producer = kwargs.pop('producer', None)
super(DoubanBookMetaSpider, self).__init__()
def isproducer(self):
return self.is_producer is not None
# (...)
此方法需要配合scrapy命令列使用,例如:
// 啟動一個生產者,producer的引數任意,只要填寫了就是True
scrapy crawl myspider -a producer=1
// 啟動一個消費者
scrapy crawl myspider
關於scrapy命令列的更多引數,參考文件:https://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/shell.html
make_request_from_data
檢視RedisMixin
中的make_request_from_data
方法註釋資訊:
Returns a Request instance from data coming from Redis.
根據來源於redis的資料返回一個Request物件
By default,
data
is an encoded URL. You can override this method to
provide your own message decoding.預設情況下,
data
是已編碼的URL連結。您可以將此方法重寫為提供您自己的訊息解碼。
def make_request_from_data(self, data):
url = bytes_to_str(data, self.redis_encoding)
return self.make_requests_from_url(url)
將data
轉為字串(網站連結字串),接著呼叫了 make_requests_from_url
,通過url
構建request
物件
data
從哪裡來?
檢視RedisMixin
的next_request
方法
由此得知,data
是從redis
中pop
出來的,在之前我們將data
序列化後push
進去,現在pop
出來,我們將其反序列化並依靠它構建request
物件
重寫make_request_from_data
def make_request_from_data(self, data):
data = pickle.loads(data, encoding=self.redis_encoding)
return self.make_request_from_book_info(data)
在本例中構建
request
物件的方法是self.make_request_from_book_info
,在實際開發中,根據目標站請求規則編寫構建request
的方法即可。
最終效果
啟動一個生成者
scrapy crawl myspider -a producer=1
生成者將所有的關鍵詞push完之後,會轉為消費者開始消費
在多個節點上啟動消費者
scrapy crawl myspider
一個爬蟲的開始,總是根據現有資料採集新的資料,例如,根據列表頁中的詳情頁連結採集詳情頁資料,根據關鍵詞采集搜尋結果等等。根據現有資料的不同,開始的方法也不同,大體仍是大同小異的。