Scrapy-Redis 空跑問題,redis_key連接跑完後,自動關閉爬蟲

首先解決爬蟲等待,不被關閉的問題:python

一、scrapy內部的信號系統會在爬蟲耗盡內部隊列中的request時,就會觸發spider_idle信號。redis

二、爬蟲的信號管理器收到spider_idle信號後,將調用註冊spider_idle信號的處理器進行處理。app

三、當該信號的全部處理器(handler)被調用後,若是spider仍然保持空閒狀態, 引擎將會關閉該spider。scrapy

scrapy-redis 中的解決方案 在信號管理器上註冊一個對應在spider_idle信號下的spider_idle()方法,當spider_idle觸發是,信號管理器就會調用這個爬蟲中的spider_idle(), Scrapy_redis 源碼以下:ide

def spider_idle(self):
        """Schedules a request if available, otherwise waits."""
        # XXX: Handle a sentinel to close the spider.
        self.schedule_next_requests()    # 這裏調用 
        schedule_next_requests() 來從redis中生成新的請求
        raise DontCloseSpider              # 拋出不要關閉爬蟲DontCloseSpider異常,保證爬蟲活着

解決思路:

  • 經過前面的瞭解,咱們知道 爬蟲關閉的關鍵是 spider_idle 信號。
  • spider_idle信號只有在爬蟲隊列爲空時纔會被觸發, 觸發間隔爲5s。
  • 那麼咱們也能夠使用一樣的方式,在信號管理器上註冊一個對應在spider_idle信號下的spider_idle()方法。
  • 在 spider_idle() 方法中,編寫結束條件來結束爬蟲,這裏以 判斷redis 中關鍵key 是否爲空,爲條件

在settings.py 文件的目錄下,建立一個名爲 extensions.py 的文件,在其中寫入如下代碼spa

# -*- coding: utf-8 -*-

# Define here the models for your scraped Extensions
import logging
import time
from scrapy import signals
from scrapy.exceptions import NotConfigured

logger = logging.getLogger(__name__)


class RedisSpiderSmartIdleClosedExensions(object):

    def __init__(self, idle_number, crawler):
        self.crawler = crawler
        self.idle_number = idle_number
        self.idle_list = []
        self.idle_count = 0

    @classmethod
    def from_crawler(cls, crawler):
        # first check if the extension should be enabled and raise

        # NotConfigured otherwise

        if not crawler.settings.getbool('MYEXT_ENABLED'):

            raise NotConfigured
        
        # 配置僅僅支持RedisSpider
        if not 'redis_key' in crawler.spidercls.__dict__.keys():

            raise NotConfigured('Only supports RedisSpider')

        # get the number of items from settings

        idle_number = crawler.settings.getint('IDLE_NUMBER', 360)

        # instantiate the extension object

        ext = cls(idle_number, crawler)

        # connect the extension object to signals

        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)

        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)

        crawler.signals.connect(ext.spider_idle, signal=signals.spider_idle)

        # return the extension object

        return ext

    def spider_opened(self, spider):
        logger.info("opened spider %s redis spider Idle, Continuous idle limit: %d", spider.name, self.idle_number)

    def spider_closed(self, spider):
        logger.info("closed spider %s, idle count %d , Continuous idle count %d",
                    spider.name, self.idle_count, len(self.idle_list))

    def spider_idle(self, spider):
        self.idle_count += 1
        self.idle_list.append(time.time())
        idle_list_len = len(self.idle_list)
       
        # 判斷 redis 中是否存在關鍵key, 若是key 被用完,則key就會不存在
        if idle_list_len > 2 and spider.server.exists(spider.redis_key):
            self.idle_list = [self.idle_list[-1]]

        elif idle_list_len > self.idle_number:
            logger.info('\n continued idle number exceed {} Times'
                        '\n meet the idle shutdown conditions, will close the reptile operation'
                        '\n idle start time: {},  close spider time: {}'.format(self.idle_number,
                                                                              self.idle_list[0], self.idle_list[0]))
            # 執行關閉爬蟲操做
            self.crawler.engine.close_spider(spider, 'closespider_pagecount')

  

在settings.py 中添加如下配置, 請將 lianjia_ershoufang 替換爲你的項目目錄名。code

MYEXT_ENABLED=True      # 開啓擴展
IDLE_NUMBER=360           # 配置空閒持續時間單位爲 360個 ,一個時間單位爲5s

# 在 EXTENSIONS 配置,激活擴展
'EXTENSIONS'= {
            'lianjia_ershoufang.extensions.RedisSpiderSmartIdleClosedExensions': 500,
        },
MYEXT_ENABLED: 是否啓用擴展,啓用擴展爲 True, 不啓用爲 False
IDLE_NUMBER: 關閉爬蟲的持續空閒次數,持續空閒次數超過IDLE_NUMBER,爬蟲會被關閉。默認爲 360 ,也就是30分鐘,一分鐘12個時間單位
相關文章
相關標籤/搜索