scrapy-redis非多網址採集的使用

mkdir700發表於2021-01-29

問題描述

預設RedisSpider在啟動時,首先會讀取redis中的spidername:start_urls,如果有值則根據url構建request物件。

現在的要求是,根據特定關鍵詞采集。

例如:目標站點有一個介面,根據post請求引數來返回結果。

那麼,在這種情況下,構建request主要的變換就是請求體(body),API介面是不變的。

對於原來通過url構建request的策略就不再適用了。

所以,此時我們需要對相應的方法進行重寫。

重寫方法

爬蟲類需要繼承至scrapy_redis.spiders.RedisSpider

start_requests

我需要從資料庫拿到關鍵詞資料,然後用關鍵詞構建請求。

此時,我們將關鍵詞看作start_url,將關鍵詞pushredis

首先,寫一個將單個關鍵詞pushredis的方法

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從哪裡來?

檢視RedisMixinnext_request方法

image-20210129114537069

由此得知,data是從redispop出來的,在之前我們將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

一個爬蟲的開始,總是根據現有資料採集新的資料,例如,根據列表頁中的詳情頁連結採集詳情頁資料,根據關鍵詞采集搜尋結果等等。根據現有資料的不同,開始的方法也不同,大體仍是大同小異的。

相關文章