[scrapy]scrapy源码分析–信号事件是如何加载以及自定义信号

环境

  • python 2.7
  • scrapy 1.3.0

背景

我们在写scrapy一些拓展功能的时候,少不了会用到scrapy的extention机制,官网也有提供各种的示例,比如我们在自己手动创建一个新的project的时候,template 会创建一个middlewares.py的文件 ,里面也会有各种和信号打交道的机制,比如这段代码

代码链接:https://github.com/scrapy/scrapy/blob/1.3/scrapy/templates/project/module/middlewares.py.tmpl

这里就直接将spider_open的”事件” 与当前的 spider open 方法链接起来了,如果还需要一些特定的信号应该如何处理呢?

意外

以上的代码是在使用scrapy 1.3.0在创建新的项目的时候会出问题TypeError: process_start_requests() takes exactly 2 arguments (3 given),一般这种问题都是没有加入self这个参数,然后在观察到官方的scrapy 1.3的template 相关的代码的时候,发现了这个错误

对于官方的这个issue,已经提了pr给它的团队: https://github.com/scrapy/scrapy/pull/2882

分析

关于信号的处理,主要由3个部分组件

  • 信号体
  • 发生方
  • 订阅方

信号体

代码所在:https://github.com/scrapy/scrapy/blob/1.3/scrapy/signals.py

以上就是目前版中常见的信号(或者说事件),拿item_scraped来说,他是怎么被发送给那些被事件订阅者的呢

发生方

代码所在:https://github.com/scrapy/scrapy/blob/eb5d396527c2d63fa6475dfd9b6372a19bce5488/scrapy/core/scraper.py

我们看到,他是使用self.signals.send_catch_log_deferred方法,将事件发送出去了,那self.signals是个啥呢?继续查看代码

self.signals = crawler.signals 是将crawler的signals赋予scraper的,这里不提不提前吐槽一下,这里的signals的变量的本质 明明就是signals_manager ,导致看的时候有点意义不明确,我们再来看crawler 的代码

代码所在:https://github.com/scrapy/scrapy/blob/master/scrapy/crawler.py

看到这里的就意义明确了,这里singals 变量,实际是实例化了SignalManager 对象,在scraper启动的时候,crawler的想关的内容都会被scraper 拿到,那SignalManager是个啥意儿,我们看看代码

基本上看到这里,我们就基本了解整个信号的运作机制了

使用pydispatch ,通过信号机制,我们轻松的将事件发生方的相关数据发送给相关的接收者

结论

如果我们要自定义一些信号,可以完全按照他的写法,来自己处理一些特定的事件或者信号机制

代码

有一个小demo 关于拿到response 的信号处理机制
代码所在:https://github.com/BruceDone/scrapy_demo/tree/master/cnblogs

参考资料

  • https://stackoverflow.com/questions/12394184/scrapy-call-a-function-when-a-spider-quits
  • https://stackoverflow.com/questions/30870872/custom-signal-not-being-handled-by-scrapy-internal-api/30871705#30871705
  • https://stackoverflow.com/questions/25169897/custom-signals-scrapy
点赞