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)

首先是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

scrapy 源码解析 (三):启动流程源码分析(三) ExecutionEngine执行引擎的更多相关文章

  1. Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段

    目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...

  2. 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码

    Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...

  3. Android Activity启动流程源码全解析(1)

    前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...

  4. Android Activity启动流程源码全解析(2)

    接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...

  5. Spark(四十九):Spark On YARN启动流程源码分析(一)

    引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...

  6. Spring IOC 容器预启动流程源码探析

    Spring IOC 容器预启动流程源码探析 在应用程序中,一般是通过创建ClassPathXmlApplicationContext或AnnotationConfigApplicationConte ...

  7. Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)

    上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...

  8. scrapy 源码解析 (二):启动流程源码分析(二) CrawlerProcess主进程

    CrawlerProcess主进程 它控制了twisted的reactor,也就是整个事件循环.它负责配置reactor并启动事件循环,最后在所有爬取结束后停止reactor.另外还控制了一些信号操作 ...

  9. scrapy 源码解析 (五):启动流程源码分析(五) Scraper刮取器

    Scraper刮取器 对ExecutionEngine执行引擎篇出现的Scraper进行展开.Scraper的主要作用是对spider中间件进行管理,通过中间件完成请求.响应.数据分析等工作. Scr ...

随机推荐

  1. [转] Socket通信实例

    点击阅读原文 Client端: #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> ...

  2. Win10下Tensorflow的安装

    Win10下Tensorflow的安装 1. Tensorflow简介 TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理.Tensor(张 ...

  3. 三星note8港版如何显示电量百分比呢?

    设置-通知-状态栏,显示电量百分比打钩即可.

  4. 【转】Windows下PATH等环境变量详解

    [转]“肖凡的专栏” 博客,请务必保留此出处http://legend2011.blog.51cto.com/3018495/553255 在学习JAVA的过程中,涉及到多个环境变量(environm ...

  5. Kali中密码暴力破解工具hydra的使用

    前言 hydra是著名黑客组织thc的一款开源的暴力破解密码工具,功能非常强大,kali下是默认安装的,几乎支持所有协议的在线破解.密码能否破解,在于字典是否强大.本文仅从安全角度去讲解工具的使用,请 ...

  6. Python 简明教程 --- 17,Python 模块与包

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 正确的判断来源于经验,然而经验来源于错误的判断. -- Fred Brooks 目录 我们已经知道函 ...

  7. Spring Bean各阶段生命周期的介绍

    一.xml方式配置bean 二.Aware接口 2.1 BeanNameAware 2.2 BeanFactoryAware 2.3 ApplicationContextAware 2.4 Aware ...

  8. 入门大数据---Scala学习

    Scala是什么? Scala是一种基于函数式编程和面向对象的高级语言.它开发了Spark等大型应用.它和Java有效集成,底层也是支持JVM的. 它有六大特性: 无缝JAVA互操作 Scala在JV ...

  9. py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe. : java.lang.IllegalArgumentException: Unsupported class file major version 55

    今天小编用Python编写Spark程序报了如下异常: py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apach ...

  10. caffe的python接口学习(5)生成deploy文件

    如果要把训练好的模型拿来测试新的图片,那必须得要一个deploy.prototxt文件,这个文件实际上和test.prototxt文件差不多,只是头尾不相同而也.deploy文件没有第一层数据输入层, ...