Scrapy框架的使用之Spider Middleware的用法

Spider Middleware是介入到Scrapy的Spider处理机制的钩子框架。我们首先来看看它的架构,如下图所示。

当Downloader生成Response之后,Response会被发送给Spider,在发送给Spider之前,Response会首先经过Spider Middleware处理,当Spider处理生成Item和Request之后,Item和Request还会经过Spider Middleware的处理。

Spider Middleware有如下三个作用。

  • 我们可以在Downloader生成的Response发送给Spider之前,也就是在Response发送给Spider之前对Response进行处理。
  • 我们可以在Spider生成的Request发送给Scheduler之前,也就是在Request发送给Scheduler之前对Request进行处理。
  • 我们可以在Spider生成的Item发送给Item Pipeline之前,也就是在Item发送给Item Pipeline之前对Item进行处理。

一、使用说明

需要说明的是,Scrapy其实已经提供了许多Spider Middleware,它们被SPIDER_MIDDLEWARES_BASE这个变量所定义。

SPIDER_MIDDLEWARES_BASE变量的内容如下:

{
    'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
    'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
    'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
    'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
}

和Downloader Middleware一样,Spider Middleware首先加入到SPIDER_MIDDLEWARES设置中,该设置会和Scrapy中SPIDER_MIDDLEWARES_BASE定义的Spider Middleware合并。然后根据键值的数字优先级排序,得到一个有序列表。第一个Middleware是最靠近引擎的,最后一个Middleware是最靠近Spider的。

二、核心方法

Scrapy内置的Spider Middleware为Scrapy提供了基础的功能。如果我们想要扩展其功能,只需要实现某几个方法即可。

每个Spider Middleware都定义了以下一个或多个方法的类,核心方法有如下4个。

  • process_spider_input(response, spider)
  • process_spider_output(response, result, spider)
  • process_spider_exception(response, exception, spider)
  • process_start_requests(start_requests, spider)

只需要实现其中一个方法就可以定义一个 Spider Middleware。下面我们来看看这4个方法的详细用法。

1. process_spider_input(response, spider)

当Response被Spider Middleware处理时,process_spider_input()方法被调用。

process_spider_input()方法的参数有如下两个。

  • response,是Response对象,即被处理的Response。
  • spider,是Spider对象,即该Response对应的Spider。

process_spider_input()应该返回None或者抛出一个异常。

  • 如果它返回None,Scrapy将会继续处理该Response,调用所有其他的Spider Middleware,直到Spider处理该Response。
  • 如果它抛出一个异常,Scrapy将不会调用任何其他Spider Middleware的process_spider_input()方法,而调用Request的errback()方法。errback的输出将会被重新输入到中间件中,使用process_spider_output()方法来处理,当其抛出异常时则调用process_spider_exception()来处理。

2. process_spider_output(response, result, spider)

当Spider处理Response返回结果时,process_spider_output()方法被调用。

process_spider_output()方法的参数有如下三个。

  • response,是Response对象,即生成该输出的Response。
  • result,包含Request或Item对象的可迭代对象,即Spider返回的结果。
  • spider,是Spider对象,即其结果对应的Spider。

process_spider_output()必须返回包含Request或Item对象的可迭代对象。

3. process_spider_exception(response, exception, spider)

当Spider或Spider Middleware的process_spider_input()方法抛出异常时,process_spider_exception()方法被调用。

process_spider_exception()方法的参数有如下三个。

  • response,是Response对象,即异常被抛出时被处理的Response。
  • exception,是Exception对象,即被抛出的异常。
  • spider,是Spider对象,即抛出该异常的Spider。

process_spider_exception()必须要么返回None,要么返回一个包含Response或Item对象的可迭代对象。

  • 如果它返回None,Scrapy将继续处理该异常,调用其他Spider Middleware中的process_spider_exception()方法,直到所有Spider Middleware都被调用。
  • 如果它返回一个可迭代对象,则其他Spider Middleware的process_spider_output()方法被调用,其他的process_spider_exception()不会被调用。

4. process_start_requests(start_requests, spider)

process_start_requests()方法以Spider启动的Request为参数被调用,执行的过程类似于process_spider_output(),只不过它没有相关联的Response,并且必须返回Request。

process_start_requests()方法的参数有如下两个。

  • start_requests,是包含Request的可迭代对象,即Start Requests。
  • spider,是Spider对象,即Start Requests所属的Spider。

process_start_requests()必须返回另一个包含Request对象的可迭代对象。

三、结语

本节介绍了Spider Middleware的基本原理和自定义Spider Middleware的方法。Spider Middleware使用的频率不如Downloader Middleware的高,在必要的情况下它可以用来方便数据的处理。

原文发布于微信公众号 - 进击的Coder(FightingCoder)

原文发表时间:2018-05-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java编程技术

常用开源框架中设计模式使用分析- 适配器模式(Adapter Pattern)

在Spring Aop框架中,MethodInterceptor接口被用来拦截指定的方法,对方法进行增强。

1202
来自专栏企鹅号快讯

聊一聊 Spring 中的线程安全性

Spring与线程安全 Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但其实,Spring并没有保证这些对象的线程安全,需要由开发...

1926
来自专栏Java与Android技术栈

RxCache 整合 Android 的持久层框架 greenDAO、Room一. 背景二. 持久层三. 使用四. 总结

RxCache 是一个支持 Java 和 Android 的 Local Cache 。

722
来自专栏XAI

微信公众号发送模板消息 Java实现。

本博文是测试公众号调用模板接口测试。请不要完全复制我的代码。里面的测试代码中有本人测试号的微信模板id。麻烦替换成自己的可以吗? 第一步:创建模板信息 ? ? ...

67111
来自专栏Phoenix的Android之旅

深入分析Java的ThreadLocal

上回书说,Android可以用Looper+Handler来实现线程通信的关键是在于Looper 回顾:深入了解Android的Looper Looper 在当...

722
来自专栏跟着阿笨一起玩NET

以读取博客园随笔备份为例 将xml 序列化成json,再序列化成对象

资源下载:http://files.cnblogs.com/codealone/ConsoleApplication2.zip

701
来自专栏Spark生态圈

[spark] 数据本地化及延迟调度

Spark数据本地化即移动计算而不是移动数据,而现实又是残酷的,不是想要在数据块的地方计算就有足够的资源提供,为了让task能尽可能的以最优本地化级别(Loca...

1552
来自专栏岑玉海

Carbondata源码系列(一)文件生成过程

在滴滴的两年一直在加班,人也变懒了,就很少再写博客了,最近在进行Carbondata和hive集成方面的工作,于是乎需要对Carbondata进行深入的研究。 ...

5446
来自专栏hbbliyong

WPF备忘录(3)如何从 Datagrid 中获得单元格的内容与 使用值转换器进行绑定数据的转换IValueConverter

一、如何从 Datagrid 中获得单元格的内容    DataGrid 属于一种 ItemsControl, 因此,它有 Items 属性并且用ItemCon...

3457
来自专栏开发技术

结合ThreadLocal来看spring事务源码,感受下清泉般的洗涤!

  在我的博客spring事务源码解析中,提到了一个很关键的点:将connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection...

1101

扫码关注云+社区