爬虫中间件

爬虫中间件的用法与下载器中间件非常相似,只是它们的作用对象不同。下载器中间件的作用对象是请求request和返回response;爬虫中间件的作用对象是爬虫,更具体地来说,就是写在spiders文件夹下面的各个文件。它们的关系,在Scrapy的数据流图上可以很好地区分开来,如下图所示。

其中,4、5表示下载器中间件,6、7表示爬虫中间件。爬虫中间件会在以下几种情况被调用。

  1. 当运行到yield scrapy.Request()或者yield item的时候,爬虫中间件的process_spider_output()方法被调用。
  2. 当爬虫本身的代码出现了Exception的时候,爬虫中间件的process_spider_exception()方法被调用。
  3. 当爬虫里面的某一个回调函数parse_xxx()被调用之前,爬虫中间件的process_spider_input()方法被调用。
  4. 当运行到start_requests()的时候,爬虫中间件的process_start_requests()方法被调用。

在中间件处理爬虫本身的异常

在爬虫中间件里面可以处理爬虫本身的异常。例如编写一个爬虫,爬取UA练习页面exercise.kingname.info/exercise_mi… ,故意在爬虫中制造一个异常,如图12-26所示。

由于网站返回的只是一段普通的字符串,并不是JSON格式的字符串,因此使用JSON去解析,就一定会导致报错。这种报错和下载器中间件里面遇到的报错不一样。下载器中间件里面的报错一般是由于外部原因引起的,和代码层面无关。而现在的这种报错是由于代码本身的问题导致的,是代码写得不够周全引起的。

为了解决这个问题,除了仔细检查代码、考虑各种情况外,还可以通过开发爬虫中间件来跳过或者处理这种报错。在middlewares.py中编写一个类:

class ExceptionCheckSpider(object):

    def process_spider_exception(self, response, exception, spider):
print(f'返回的内容是:{response.body.decode()}\n报错原因:{type(exception)}')
return None
复制代码

这个类仅仅起到记录Log的作用。在使用JSON解析网站返回内容出错的时候,将网站返回的内容打印出来。

process_spider_exception()这个方法,它可以返回None,也可以运行yield item语句或者像爬虫的代码一样,使用yield scrapy.Request()发起新的请求。如果运行了yield item或者yield scrapy.Request(),程序就会绕过爬虫里面原有的代码。

例如,对于有异常的请求,不需要进行重试,但是需要记录是哪一个请求出现了异常,此时就可以在爬虫中间件里面检测异常,然后生成一个只包含标记的item。还是以抓取exercise.kingname.info/exercise_mi…这个练习页的内容为例,但是这一次不进行重试,只记录哪一页出现了问题。先看爬虫的代码,这一次在meta中把页数带上,如下图所示。

![img](data:image/svg+xml;utf8,)

爬虫里面如果发现了参数错误,就使用raise这个关键字人工抛出一个自定义的异常。在实际爬虫开发中,读者也可以在某些地方故意不使用try ... except捕获异常,而是让异常直接抛出。例如XPath匹配处理的结果,直接读里面的值,不用先判断列表是否为空。这样如果列表为空,就会被抛出一个IndexError,于是就能让爬虫的流程进入到爬虫中间件的process_spider_exception()中。

在items.py里面创建了一个ErrorItem来记录哪一页出现了问题,如下图所示。

![img](data:image/svg+xml;utf8,)

接下来,在爬虫中间件中将出错的页面和当前时间存放到ErrorItem里面,并提交给pipeline,保存到MongoDB中,如下图所示。

![img](data:image/svg+xml;utf8,)

这样就实现了记录错误页数的功能,方便在后面对错误原因进行分析。由于这里会把item提交给pipeline,所以不要忘记在settings.py里面打开pipeline,并配置好MongoDB。储存错误页数到MongoDB的代码如下图所示。

![img](data:image/svg+xml;utf8,)

激活爬虫中间件

爬虫中间件的激活方式与下载器中间件非常相似,在settings.py中,在下载器中间件配置项的上面就是爬虫中间件的配置项,它默认也是被注释了的,解除注释,并把自定义的爬虫中间件添加进去即可,如下图所示。

Scrapy也有几个自带的爬虫中间件,它们的名字和顺序如下图所示。

下载器中间件的数字越小越接近Scrapy引擎,数字越大越接近爬虫。如果不能确定自己的自定义中间件应该靠近哪个方向,那么就在500~700之间选择最为妥当。

爬虫中间件输入/输出

在爬虫中间件里面还有两个不太常用的方法,分别为process_spider_input(response, spider)process_spider_output(response, result, spider)。其中,process_spider_input(response, spider)在下载器中间件处理完成后,马上要进入某个回调函数parse_xxx()前调用。process_spider_output(response, result, output)是在爬虫运行yield item或者yield scrapy.Request()的时候调用。在这个方法处理完成以后,数据如果是item,就会被交给pipeline;如果是请求,就会被交给调度器,然后下载器中间件才会开始运行。所以在这个方法里面可以进一步对item或者请求做一些修改。这个方法的参数result就是爬虫爬出来的item或者scrapy.Request()。由于yield得到的是一个生成器,生成器是可以迭代的,所以result也是可以迭代的,可以使用for循环来把它展开。

def process_spider_output(response, result, spider):
for item in result:
if isinstance(item, scrapy.Item):
# 这里可以对即将被提交给pipeline的item进行各种操作
print(f'item将会被提交给pipeline')
yield item
复制代码

或者对请求进行监控和修改:

def process_spider_output(response, result, spider):
for request in result:
if not isinstance(request, scrapy.Item):
# 这里可以对请求进行各种修改
print('现在还可以对请求对象进行修改。。。。')
request.meta['request_start_time'] = time.time()
yield request

作者:青南

链接:https://juejin.im/post/5bf4a3846fb9a049fe34c413

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Scrapy的中间件(二)的更多相关文章

  1. 彻底搞懂Scrapy的中间件(一)

    中间件是Scrapy里面的一个核心概念.使用中间件可以在爬虫的请求发起之前或者请求返回之后对数据进行定制化修改,从而开发出适应不同情况的爬虫. "中间件"这个中文名字和前面章节讲到 ...

  2. scrapy之中间件

    中间件的简介 1.中间件的作用 在scrapy运行的整个过程中,对scrapy框架运行的某些步骤做一些适配自己项目的动作. 例如scrapy内置的HttpErrorMiddleware,可以在http ...

  3. scrapy的中间件Downloader Middleware实现User-Agent随机切换

    scrapy的中间件Download Middleware实现User-Agent随机切换   总架构理解Middleware 通过scrapy官网最新的架构图来理解: 从图中我们可以看出,在spid ...

  4. scrapy框架中间件配置代理

    scrapy框架中间件配置代理import random#代理池PROXY_http = [ '106.240.254.138:80', '211.24.102.168:80',]PROXY_http ...

  5. 初试kafka消息队列中间件二(采用java代码收发消息)

    初试kafka消息队列中间件二(采用java代码收发消息) 上一篇 初试kafka消息队列中间件一 今天的案例主要是将采用命令行收发信息改成使用java代码实现,根据上一篇的接着写: 先启动Zooke ...

  6. scrapy框架(二)

    scrapy框架(二) 一.scrapy 选择器 概述: Scrapy提供基于lxml库的解析机制,它们被称为选择器. 因为,它们“选择”由XPath或CSS表达式指定的HTML文档的某部分. Sca ...

  7. Scrapy的中间件(一)

    中间件是Scrapy里面的一个核心概念.使用中间件可以在爬虫的请求发起之前或者请求返回之后对数据进行定制化修改,从而开发出适应不同情况的爬虫. "中间件"这个中文名字和前面章节讲到 ...

  8. Scrapy下载中间件的优先级(神踏马值越小优先级越高)

    自从之前看的一篇讲Scrapy下载中间件的文章后,一直认为设置里下载中间件的优先级数值越小,越优先,最近要抓的网站反爬增强了,所以需要使用代理ip,但是由于使用的是免费代理以至于经常失效,需要对失效的 ...

  9. Python爬虫从入门到放弃(二十三)之 Scrapy的中间件Downloader Middleware实现User-Agent随机切换

    总架构理解Middleware 通过scrapy官网最新的架构图来理解: 这个图较之前的图顺序更加清晰,从图中我们可以看出,在spiders和ENGINE提及ENGINE和DOWNLOADER之间都可 ...

  10. 彻底搞懂Scrapy的中间件(二)

    在上一篇文章中介绍了下载器中间件的一些简单应用,现在再来通过案例说说如何使用下载器中间件集成Selenium.重试和处理请求异常. 在中间件中集成Selenium 对于一些很麻烦的异步加载页面,手动寻 ...

随机推荐

  1. Python连载28-logging设置&logger解析

    一.logging模块讲解 1.函数:logging.basicConfig() 参数讲解: (1)level代表高于或者等于这个值时,那么我们才会记录这条日志 (2)filename代表日志会写在这 ...

  2. 安装Office 2016 出现 Office 16 Click-to-Run Extensibility Component

    无法安装 64 位版本的 Office,因为在您的 PC 上找到了以下 32 位程序: Office 16 Click-to-Run Extensibility Component 请卸载所有 32 ...

  3. 使用linux/macos 自带的shell实现证书方式的快速登陆

    一般登陆机器都是需要使用证书安全登陆到跳板机上然后在跳板机去登陆到各个机器. 我们建立一个统一的文件夹mykey,将登陆的pem证书放上去,然后创建一个空白的文件,vim jump.sh #!/usr ...

  4. 『kamp 树形dp』

    kamp Description jz 市的云台山是个很美丽的景区,小 x 暑期到云台山打工,他的任务是开景区的大巴. 云台山景区有 N 个景点,这 N 个景点由 N-1 条道路连接而成,我们保证这 ...

  5. struts2拦截器的实现机制

    前言 最近老大让每周写一篇技术性的博客,想想也没啥写,就想着随便拿个以前的项目去研究研究五大框架的底层代码.本人水平有限,有不对的地方还望大家勿喷,指正! 开始之前先了解下strtus2的工作流程: ...

  6. C# vb .NET读取识别条形码线性条码CODE93

    code93是比较常见的条形码编码规则类型的一种.如何在C#,vb等.NET平台语言里实现快速准确读取该类型条形码呢?答案是使用SharpBarcode! SharpBarcode是C#快速高效.准确 ...

  7. 添加wcf服务引用,无法签出当前文件

    写了一些wcf服务接口,使用控制台可以正常启动服务,想要测试一下,新建项目添加服务引用,提示:“无法签出当前文件.该文件可能为只读或已锁定,或者您需要手动签出它.” 在网上找了找,有说可能是因为源代码 ...

  8. mvc中ViewBag返回数组如何循环显示数据

    直接在for循环里面定义出viewbag @for (int i = 0; i < ViewBag.permission.Count; i++) { var permission = ViewB ...

  9. linux系统shell基础知识入门二

    条件判断语句 test或[],这两是等价的.但用[]这种可能看起来更简洁 必须在[符号和检查条件之间留出空格,而test命令之后也总是应该有一个空格 如果要把test 和then 放一行上,那么必须在 ...

  10. 藏红花StigmaCroci西红花StigmaCroci番红花

    伊朗藏红花(StigmaCroci)是一种耐旱植物,适于生长在冬季最低气温不低于零下20度,夏季最高气温不高于零上35度且气候干燥的地区. 因其水土和气候条件的限制,除了伊朗能大量种植外,希腊.印度. ...