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

問題描述

默認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命令行的更多參數,參考文檔://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

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