zoukankan      html  css  js  c++  java
  • scrapy 源码解析 (三):启动流程源码分析(三) ExecutionEngine执行引擎

    ExecutionEngine执行引擎

    上一篇分析了CrawlerProcess和Crawler对象的建立过程,在最终调用CrawlerProcess.start()之前,会首先建立ExecutionEngine执行引擎,执行其open_spider和start方法。

    ExecutionEngine.open_spiders()

    scrapy/core/engine.py#ExecutionEngine:

        @defer.inlineCallbacks
        def open_spider(self, spider, start_requests=(), close_if_idle=True):
            assert self.has_capacity(), "No free spider slot when opening %r" % 
                spider.name
            logger.info("Spider opened", extra={'spider': spider})
            nextcall = CallLaterOnce(self._next_request, spider)
            scheduler = self.scheduler_cls.from_crawler(self.crawler)
            start_requests = yield self.scraper.spidermw.process_start_requests(start_requests, spider)
            slot = Slot(start_requests, close_if_idle, nextcall, scheduler)
            self.slot = slot
            self.spider = spider
            yield scheduler.open(spider)
            yield self.scraper.open_spider(spider)
            self.crawler.stats.open_spider(spider)
            yield self.signals.send_catch_log_deferred(signals.spider_opened, spider=spider)
            slot.nextcall.schedule()
            slot.heartbeat.start(5)
    View Code

    首先是nextcall = CallLaterOnce(self._next_request, spider),nextcall在后面注册到Slot对象里:
    scrapy/utils/reactor.py#CallLaterOnce:

    class CallLaterOnce(object):
        def __init__(self, func, *a, **kw):
            self._func = func
            self._a = a
            self._kw = kw
            self._call = None
        def schedule(self, delay=0):
            if self._call is None:
                self._call = reactor.callLater(delay, self)
        def cancel(self):
            if self._call:
                self._call.cancel()
        def __call__(self):
            self._call = None
            return self._func(*self._a, **self._kw)

    scrapy/utils/reactor.py#Slot:

    class Slot(object):
        def __init__(self, start_requests, close_if_idle, nextcall, scheduler):
            self.closing = False
            self.inprogress = set() # requests in progress
            self.start_requests = iter(start_requests)
            self.close_if_idle = close_if_idle
            self.nextcall = nextcall
            self.scheduler = scheduler
            self.heartbeat = task.LoopingCall(nextcall.schedule)

    CallLaterOnce与Slot的共同作用是:
    slot代表一次nextcall的执行,实际上就是执行一次engine的_next_request。slot创建了一个hearbeat,即为一个心跳。通过twisted的task.LoopingCall实现。
    每隔5s执行一次,尝试处理一个新的request,这属于被动执行。后面还会有主动执行的代码。
    slot可以理解为一个request的生命周期。

    继续看ExecutionEngine里的代码:

    scheduler = self.scheduler_cls.from_crawler(self.crawler)
    start_requests = yield self.scraper.spidermw.process_start_requests(start_requests, spider)

    创建一个scheduler(scrapy框架里的许多组件如spider/middleware/scheduler都会有from_crawler这个默认方法)。这里的scheduler是从配置里取的,默认为SCHEDULER = ‘scrapy.core.scheduler.Scheduler’;
    然后调用scraper的spidermw的process_tart_requests方法来处理start_requests。
    scraper的作用前面也有介绍是对下载的网页的解析结果进行itemPipeLine的处理,通常是数据库操作;它的spidermw也就是中间件管理器,其实就是SpiderMiddlewareManager,用它来调用每个注册的中间件的process_start_requests方法来处理初始请求。如果我们要对start_requests进行特殊处理,可以自己实现中间件并实现process_start_requests方法。
    继续:

    yield scheduler.open(spider)
    yield self.scraper.open_spider(spider)

    依次调用scheduler的open方法和scraper的open_spider方法。

    yield self.signals.send_catch_log_deferred(signals.spider_opened, spider=spider)

    发送一个spider_opened消息并记录日志,所有关注这个消息的函数都会被调用(写了此函数的各种中间件),同时会向关注模块注册的函数传递一个spider变量。

    最后是下面2行代码:

    slot.nextcall.schedule()
    slot.heartbeat.start(5)

    前面已经分析过nextcall和slot,所以这2行的作用就是调用reactor.callLater(delay, self)并设置心跳为5秒。其实这只是作了初始化操作,进行了函数的安装,实际运行要等到reactor启动,也就是前面分析过的CrawlerProcess调用start时。

    ExecutionEngine.start()

        @defer.inlineCallbacks
        def start(self):
            """Start the execution engine"""
            assert not self.running, "Engine already running"
            self.start_time = time()
            yield self.signals.send_catch_log_deferred(signal=signals.engine_started)
            self.running = True
            self._closewait = defer.Deferred()
            yield self._closewait

    代码很简单:记录启动时间;发送一个"engine_started"消息;设置running标志;创建一个_closewait的Deferred对象并返回。
    这个_closewait从前面的代码分析中可知会返回给CrawlerProcess,这个Deferred在引擎结束时才会调用,因此用它来向CrawlerProcess通知一个Crawler已经爬取完毕。
    ————————————————
    版权声明:本文为CSDN博主「csdn_yym」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/csdn_yym/java/article/details/85575921

  • 相关阅读:
    C++异常第二篇---C++标准库异常类exception的使用
    C++异常(exception)第一篇--综合讲解
    libconfig第二篇----两个小例子
    libconfig第一篇———使用指南
    log4cxx第三篇----使用多个logger
    kafka第五篇
    kafka第四篇--快速入门(如何使用kafka)
    UVA 455(最小周期)
    UVA1584(环状序列)
    UVA1583(最小生成元)
  • 原文地址:https://www.cnblogs.com/qiu-hua/p/12930803.html
Copyright © 2011-2022 走看看