• 欢迎来到本博客,希望可以y一起学习与分享

scrapy进阶(六)–数据收集(Stats Collection)与信号(Signals)与扩展(Extensions)

Python benz 3年前 (2018-10-21) 83次浏览 0个评论 扫描二维码
文章目录[隐藏]

数据收集(Stats Collection)

Scrapy提供了方便的收集数据的机制。数据以key/value方式存储,值大多是计数值。 该机制叫做数据收集器(Stats Collector),可以通过 Crawler API 的属性 stats 来使用。在下面的章节 常见数据收集器使用方法 将给出例子来说明。

无论数据收集(stats collection)开启或者关闭,数据收集器永远都是可用的。 因此您可以import进自己的模块并使用其API(增加值或者设置新的状态键(stat keys))。 该做法是为了简化数据收集的方法: 您不应该使用超过一行代码来收集您的spider,Scrpay扩展或任何您使用数据收集器代码里头的状态。

数据收集器的另一个特性是(在启用状态下)很高效,(在关闭情况下)非常高效(几乎察觉不到)。

数据收集器对每个spider保持一个状态表。当spider启动时,该表自动打开,当spider关闭时,自动关闭。
这个东西大部分用在计数上,比如成功多少次,失败多少次,收集了多少item之类。

常见数据收集器使用方法

通过 stats 属性来使用数据收集器。 下面是在扩展中使用状态的例子:

设置数据:

增加数据值:

当新的值比原来的值大时设置数据:

当新的值比原来的值小时设置数据:

获取数据:

获取所有数据:

可用的数据收集器

除了基本的 StatsCollector,Scrapy 也提供了基于 StatsCollector 的数据收集器。 您可以通过 STATS_CLASS 设置来选择。默认使用的是 MemoryStatsCollector

MemoryStatsCollector

class scrapy.statscol.MemoryStatsCollector

一个简单的数据收集器。其在 spider 运行完毕后将其数据保存在内存中。数据可以通过 spider_stats 属性访问。该属性是一个以 spider 名字为键(key)的字典。

这是 Scrapy 的默认选择。
spider_stats
保存了每个 spider 最近一次爬取的状态的字典(dict)。该字典以 spider 名字为键,值也是字典。

DummyStatsCollector

class scrapy.statscol.DummyStatsCollector

该数据收集器并不做任何事情但非常高效。您可以通过设置 STATS_CLASS 启用这个收集器,来关闭数据收集,提高效率。 不过,数据收集的性能负担相较于 Scrapy 其他的处理(例如分析页面)来说是非常小的。

使用实例,统计处理404页面

信号(Signals)

Scrapy 使用信号来通知事情发生。您可以在您的 Scrapy 项目中捕捉一些信号(使用 extension)来完成额外的工作或添加额外的功能,扩展 Scrapy。

虽然信号提供了一些参数,不过处理函数不用接收所有的参数 – 信号分发机制(singal dispatching mechanism)仅仅提供处理器(handler)接受的参数。

您可以通过信号(Signals) API 来连接(或发送您自己的)信号。

延迟的信号处理器(Deferred signal handlers)

有些信号支持从处理器返回 Twisted deferreds,参考下边的内置信号参考手册(Built-in signals reference)来了解哪些支持。

内置信号参考手册(Built-in signals reference)

以下给出 Scrapy 内置信号的列表及其意义。

engine_started

scrapy.signals.engine_started()
当 Scrapy 引擎启动爬取时发送该信号。

该信号支持返回 deferreds。

注解

该信号可能会在信号 spider_opened 之后被发送,取决于 spider 的启动方式。 所以不要 依赖 该信号会比 spider-opened 更早被发送。

engine_stopped

scrapy.signals.engine_stopped()
当 Scrapy 引擎停止时发送该信号(例如,爬取结束)。

该信号支持返回 deferreds。

item_scraped

scrapy.signals.item_scraped(item, response, spider)
当 item 被爬取,并通过所有 Item Pipeline 后(没有被丢弃(dropped),发送该信号。

该信号支持返回 deferreds。

参数:

  • item (Item 对象) – 爬取到的 item
  • spider (Spider 对象) – 爬取 item 的 spider
  • response (Response 对象) – 提取 item 的 response

item_dropped

scrapy.signals.item_dropped(item, exception, spider)
当 item 通过 Item Pipeline,有些 pipeline 抛出 DropItem 异常,丢弃 item 时,该信号被发送。

该信号支持返回 deferreds。

参数:

  • item (Item 对象) – 爬取到的 item
  • spider (Spider 对象) – 爬取 item 的 spider
  • exception (DropItem 异常) – 导致 item 被丢弃的异常(必须是 DropItem 的子类)

spider_closed

scrapy.signals.spider_closed(spider, reason)
当某个 spider 被关闭时,该信号被发送。该信号可以用来释放每个 spider 在 spider_opened 时占用的资源。

该信号支持返回 deferreds。

参数:

  • spider (Spider 对象) – 关闭的 spider
  • reason (str) – 描述 spider 被关闭的原因的字符串。如果 spider 是由于完成爬取而被关闭,则其为'finished'。否则,如果 spider 是被引擎的 close_spider 方法所关闭,则其为调用该方法时传入的 reason 参数(默认为'cancelled')。如果引擎被关闭(例如, 输入 Ctrl-C),则其为'shutdown'

spider_opened

scrapy.signals.spider_opened(spider)
当 spider 开始爬取时发送该信号。该信号一般用来分配 spider 的资源,不过其也能做任何事。

该信号支持返回 deferreds。

参数:

  • spider (Spider 对象) – 开启的 spider

spider_idle

scrapy.signals.spider_idle(spider)
当 spider 进入空闲(idle)状态时该信号被发送。空闲意味着:

  • requests 正在等待被下载
  • requests 被调度
  • items 正在 item pipeline 中被处理

当该信号的所有处理器(handler)被调用后,如果 spider 仍然保持空闲状态,引擎将会关闭该 spider。当 spider 被关闭后,spider_closed 信号将被发送。

您可以,比如,在 spider_idle 处理器中调度某些请求来避免 spider 被关闭。

该信号不支持返回 deferreds。

参数:

  • spider (Spider 对象) – 空闲的 spider

spider_error

scrapy.signals.spider_error(failure, response, spider)
当 spider 的回调函数产生错误时(例如,抛出异常),该信号被发送。

参数:

  • failure (Failure 对象) – 以 Twisted Failure 对象抛出的异常
  • response (Response 对象) – 当异常被抛出时被处理的 response
  • spider (Spider 对象) – 抛出异常的 spider

request_scheduled

scrapy.signals.request_scheduled(request, spider)
当引擎调度一个 Request 对象用于下载时,该信号被发送。

该信号 不支持 返回 deferreds。

参数:

  • request (Request 对象) – 到达调度器的 request
  • spider (Spider 对象) – 产生该 request 的 spider

request_dropped

scrapy.signals.request_dropped(request, spider)

当调度器拒绝稍后将要下载的请求时发送。

该信号 不支持 返回deferreds。

参数:

  • request (Request object) – the request that reached the scheduler
  • spider (Spider object) – the spider that yielded the request

response_received

scrapy.signals.response_received(response, request, spider)
当引擎从 downloader 获取到一个新的 Response 时发送该信号。

该信号 不支持 返回 deferreds。

参数:

  • response (Response 对象) – 接收到的 response
  • request (Request 对象) – 生成 response 的 request
  • spider (Spider 对象) – response 所对应的 spider

response_downloaded

scrapy.signals.response_downloaded(response, request, spider)
当一个 HTTPResponse 被下载时,由 downloader 发送该信号。

该信号 不支持 返回 deferreds。

参数:

  • response (Response 对象) – \下载的 response
  • request (Request 对象) – 生成 response 的 request
  • spider (Spider 对象) – response 所对应的 spider

示例

我将这段代码放到中间件里,本来应该是,再与setting同级的目录下创建一个py文件,然后来写的。
然后再在setting的 EXTENSIONS 里启用并给出等级,就像piplin和middleware一样。

扩展(Extensions)

扩展框架提供一个机制,使得你能将自定义功能绑定到 Scrapy。

扩展只是正常的类,它们在 Scrapy 启动时被实例化、初始化。

扩展设置(Extension settings)

扩展使用 Scrapy settings 管理它们的设置,这跟其他 Scrapy 代码一样。

通常扩展需要给它们的设置加上前缀,以避免跟已有(或将来)的扩展冲突。 比如,一个扩展处理 Google Sitemaps,则可以使用类似 GOOGLESITEMAP_ENABLED、GOOGLESITEMAP_DEPTH 等设置。

加载和激活扩展

扩展在扩展类被实例化时加载和激活。 因此,所有扩展的实例化代码必须在类的构造函数(__init__)中执行。

要使得扩展可用,需要把它添加到 Scrapy 的 EXTENSIONS 配置中。在 EXTENSIONS 中,每个扩展都使用一个字符串表示,即扩展类的全 Python 路径。比如:

如你所见,EXTENSIONS 配置是一个 dict,key 是扩展类的路径,value 是顺序,它定义扩展加载的顺序。扩展顺序不像中间件的顺序那么重要,而且扩展之间一般没有关联。扩展加载的顺序并不重要,因为它们并不相互依赖。

如果你需要添加扩展而且它依赖别的扩展,你就可以使用该特性了。

这也是为什么 Scrapy 的配置项 EXTENSIONS_BASE(它包括了所有内置且开启的扩展)定义所有扩展的顺序都相同(500)。

可用的(Available)、开启的(enabled)和禁用的(disabled)的扩展

并不是所有可用的扩展都会被开启。一些扩展经常依赖一些特别的配置。 比如,HTTP Cache 扩展是可用的但默认是禁用的,除非 HTTPCACHE_ENABLED 配置项设置了。

禁用扩展(Disabling an extension)

为了禁用一个默认开启的扩展(比如,包含在 EXTENSIONS_BASE 中的扩展),需要将其顺序(order)设置为 None。比如:

实现你的扩展

实现你的扩展很简单。每个扩展是一个单一的 Python class,它不需要实现任何特殊的方法。

Scrapy 扩展(包括 middlewares 和 pipelines)的主要入口是 from_crawler 类方法,它接收一个 Crawler 类的实例,该实例是控制 Scrapy crawler 的主要对象。如果扩展需要,你可以通过这个对象访问 settings,signals,stats,控制爬虫的行为。

通常来说,扩展关联到 signals 并执行它们触发的任务。

最后,如果 from_crawler 方法抛出 NotConfigured 异常,扩展会被禁用。否则,扩展会被开启。

示例

解释

Scrapy API的主要入口是 Crawler 的实例对象, 通过类方法 from_crawler 将它传递给扩展(extensions),详细解释参见这里

所以第一步通过from_crawler类方法获取到Crawler对象。

  • 我的理解是当项目启动后就开启了一个抓取的行为这个行为通过Crawler对象来管理,表现为对spider的控制和状态指示。

之后通过from_crawler类方法获取的crawler注册信号处理方法:

这里对应的信号spider_opened注册为instancespider_opened方法,信号spider_closed注册为instancespider_closed方法。

  • spider_opened 信号在爬虫开启时由spider发送。
  • spider_closed 信号在爬虫结束时由spider发送。

而 instance 是通过instance = cls(crawler.stats)实例化的本扩展的一个实例。作用在于将crawler.stats传递给本扩展,并暴露自己的方法用于crawler信号的注册。

这样启动项目后spider发送spider_opened信号,本扩展会接收到这个信号执行绑定的spider_opened方法:

通过这个方法打开一个定时任务,间隔60秒执行一次本扩展的collect方法打印spider的状态:

同理,spider关闭后,扩展接收到spider_closed信号,执行本扩展的spider_closed方法关闭这个定时任务。


文章 scrapy进阶(六)–数据收集(Stats Collection)与信号(Signals)与扩展(Extensions) 转载需要注明出处
喜欢 (0)

您必须 登录 才能发表评论!