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)
首先是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执行引擎的更多相关文章
- Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段
目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...
- 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码
Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...
- Android Activity启动流程源码全解析(1)
前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...
- Android Activity启动流程源码全解析(2)
接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...
- Spark(四十九):Spark On YARN启动流程源码分析(一)
引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...
- Spring IOC 容器预启动流程源码探析
Spring IOC 容器预启动流程源码探析 在应用程序中,一般是通过创建ClassPathXmlApplicationContext或AnnotationConfigApplicationConte ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- scrapy 源码解析 (二):启动流程源码分析(二) CrawlerProcess主进程
CrawlerProcess主进程 它控制了twisted的reactor,也就是整个事件循环.它负责配置reactor并启动事件循环,最后在所有爬取结束后停止reactor.另外还控制了一些信号操作 ...
- scrapy 源码解析 (五):启动流程源码分析(五) Scraper刮取器
Scraper刮取器 对ExecutionEngine执行引擎篇出现的Scraper进行展开.Scraper的主要作用是对spider中间件进行管理,通过中间件完成请求.响应.数据分析等工作. Scr ...
随机推荐
- ESP8266局域网智能家居 路由器下作服务器模式串口透传 无线通信控制 arduino uno示例 模板参考
准备工作 下载一个Arduino IDE, 下载8266的库文件 ESP8266服务器模式串口透传编译 功能说明 1.直接使用路由器中转数据 2.手机放热点模式直接传输数据 两者有访问IP地址的差别, ...
- 几款一元单片机对比:CMS8S5880、STM8S003、N76E003
大概17年开始,STM8S003的价格被贸易商炒货,变得很不稳定,一度上涨到2~3元,因为市场需求大增,小家电.无线充和一些简单功能的产品,本人就有在空气净化器.433M触摸开关.数据收发模块.红外控 ...
- 四分位数与pandas中的quantile函数
四分位数与pandas中的quantile函数 1.分位数概念 统计学上的有分位数这个概念,一般用p来表示.原则上p是可以取0到1之间的任意值的.但是有一个四分位数是p分位数中较为有名的. 所谓四分位 ...
- Ray射线检测和Recources.Load
记录射线检测常用的方法,以及Rocources.Load的常用用法 使用代码实现鼠标点击在鼠标点击处生成制定gameObject RayCastHit hit; void Update() { Ray ...
- WeChair项目Alpha冲刺(4/10)
团队项目进行情况 1.昨日进展 Alpha冲刺第四天 昨日进展: 前端完成小程序登录态的定义 LoginController编写初步完成同时修改并更新了代码,但是在将编码好的项目部署到服务器上时 ...
- 键盘侠Linux干货| 使用SSH方式推送文件至github仓库
前言 作为一名优秀的计算机从业人员,相信大家github应该都知道吧.(优秀的代码托管工具) 但是由于平常使用的https方式克隆的本地仓库,每次git push时都需要输入帐号密码才能将我们修改的文 ...
- ASP.NET WebAPI框架解析第一篇
ASP.NET WebAPI有两种寄宿模式,一种是WebHost,一种是SelfHost,为什么可以有两种模式的原因在于WebAPI有一个相对独立的消息处理管道,只要给这个消息管道传递一个封装好的对象 ...
- opencv C++构造并访问单通道和多通道Mat。
一:构造并访问单通道. int main(){ cv::Mat m=(cv::Mat_<int>(3,2)<<1,2,3,4,5,6); for(int i=0;i<m. ...
- 尚硅谷maven视频教程笔记
07.尚硅谷_Maven_部署Maven核心程序.avi 第一步先安装jdk 第二步下载maven 特别需要注意的是maven不能存储在有中文和空格的目录下面 3.调试是否安装成功,在cmd中输入 m ...
- ant+jmeter+jenkins接口自动化测试一
[Jmeter篇]jmeter+Ant+Jenkins接口自动化测试集成(一) 橙子探索测试发表于橙子探索测试订阅 90 一.简介 1.什么是ant? ant是构建工具,把代码从某个地方拿来,编译,再 ...