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. 网络聚合Network Teaming

    team是新的聚合软件,依赖于安装包teamd,可以通过nmcli管理. team和bond的区别在于,支持hash加密,支持负载均衡,支持8块网卡,更好地支持IPV6,总之要取代bond. 1. 添 ...

  2. @topcoder - 2013TCO3A D1L3@ TrickyInequality

    目录 @description@ @accepted code@ @accepted code@ @details@ @description@ 现有不等式组: \[\begin{cases} x_1 ...

  3. LR脚本信息函数-lr_start_timer和lr_end_timer

    为了计算时间更加精确,可以用这个函数去掉LR自身的检查点所浪费的时间.如text check and image time Action() { double time_elapsed, durati ...

  4. C++值元编程

    --永远不要在OJ上使用值元编程,过于简单的没有优势,能有优势的编译错误. 背景 2019年10月,我在学习算法.有一道作业题,输入规模很小,可以用打表法解决.具体方案有以下三种: 运行时预处理,生成 ...

  5. laravel查询常用的方式含义.

    find($id) 传值并返回一个模型.如果不存在匹配的模型,则返回null.findOrFail($id) 传值并返回一个模型.如果不存在匹配的模型, 它会抛出异常.first() 返回在数据库中找 ...

  6. 11.实战交付一套dubbo微服务到k8s集群(4)之使用Jenkins进行持续构建交付dubo服务的提供者

    1.登录到jenkins,新建一个项目 2.新建流水线 3.设置保留的天数及份数 4. 添加参数 # 参数 . name: git_repo type: string description: 项目在 ...

  7. Centos7.X 搭建Grafana+Jmeter+Influxdb 性能实时监控平台(不使用docker)

    工具介绍 [centos7安装influxDB] Influxdata官网下载路径:https://portal.influxdata.com/downloads/ 1.直接执行以下命令安装 2.安装 ...

  8. netty--helloword程序

    1.使用netty需要使用到下面的java包 netty-all-5.0.0.Alpha2.jar 我们来看下面具体的代码 1. 创建一个ServerBootstrap实例 2. 创建一个EventL ...

  9. IOT设备SmartConfig实现

    一般情况下,IOT设备(针对wifi设备)在智能化过程中需要连接到家庭路由.但在此之前,需要将wifi信息(通常是ssid和password,即名字和密码)发给设备,这一步骤被称为配网.移动设备如An ...

  10. 在Github上建立自己的个人主页

    目录 注册Github账号 登录Github账号 建立新仓库 选择个人主页的主题 注册Github账号 首先打开Github的主页(https://github.com/),点击右上角的sign up ...