scrapy-redis非多網址採集的使用
問題描述
默認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命令行的更多參數,參考文檔://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
一個爬蟲的開始,總是根據現有數據採集新的數據,例如,根據列表頁中的詳情頁鏈接採集詳情頁數據,根據關鍵詞採集搜索結果等等。根據現有數據的不同,開始的方法也不同,大體仍是大同小異的。