详解 Scrapy 中间键的用法

Scrapy 爬虫框架的出现,确实能让我们更加专注于数据抓取。同时,我们借助 Scrapy 框架来爬取整个站点数据也显得更加容易。虽然 Scarpy 负责 url 调度、网络请求、页面数据下载等工作,但是它的扩展性很高,其中就支持自定义中间件(Middleware)。本文主要讲解中间件(Middleware)的用法。

01

什么是中间件

中间件的运用比较广泛,如果直接从定义的角度去理解中间件会有点乱,我以分布式系统为例子进行说明。在上篇文章,我讲到目前后台服务架构基本都是往分布式发展。其实分布式系统也算是一个中间件。

那什么是分布式系统?分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。我们从下图中可得知,分布式系统是介于操作系统和用户应用之间的软件。

那么不妨我们进一步拓展下思维去理解中间件。可知,中间件(middleware)是基础软件的一大类,属于可复用软件的范畴。顾名思义,中间件处于操作系统软件与用户的应用软件的中间。

02

中间件在Scrapy框架中的作用

我们先通过一张图了解下 Scrapy 架构。

我们可以看到 Scrapy 框架是有两个中间件。 一个是 Downloader 中间件,它是 Engine 和 Downloader 的枢纽。主要负责处理 Downloader 传递给 Engine 的 responses;

另一个是 Spider 中间件,它Spider 中间件是 Engine 和 Spider 的连接桥梁;它主要是处理 Spider 的输入(responses) 以及输出 item 和 requests 给 Engine;

03

实现自己的中间件

在 Scrapy 框架中,Downloader 中间件和 Spider 中间件都是支持自定义扩展。在实际应用中,我们经常需要对 Downloader 中间件进行制定化。例如实现一个 User-Agent 中间件给每个 HTTP 请求的头部增加随机筛选的 User-Agent 属性;或者实现一个代理中间件给每个 HTTP 请求设置随机选择的代理地址。

接下来,让我们学习如何实现 Scrapy 的 Downloader 中间件。 1) 定义中间件 在 Scrapy 项目中,找到 middlewares.py 文件,在文件中创建自己的中间件类。例如,我创建一个代理中间件:

class ProxyMiddleware(object):

每个中间件一共有三个方法,分别是:

  • process_request(request,spider)

当每个 request 通过下载中间件时,该方法被调用。该方法必须返回以下三种中的任意一种:None,返回一个 Response 对象,返回一个 Request 对象或 raise IgnoreRequest。每种返回值的作用是不同的。

None: Scrapy 将会继续处理该 request,执行其他的中间件的相应方法,直到合适的下载器处理函数( download handler )被调用,该 request 被执行(其 response被下载)。如果有多个中间件,其他的中间件可以通过返回 Null,然后指定对应的中间件去处理 request

Request 对象:Scrapy 则停止调用 process_request 方法并重新调度返回的 request。简单来说是拒绝该 Request 的 HTTP 请求。

Response 对象:直接返回结果。

raise IgnoreRequest 异常:抛出异常,然后会被中间件的 process_exception() 方法会被调用。

  • process_response(request, response, spider)

process_response 的返回值也是有三种:Response 对象,Request对象,或者 raise 一个 IgnoreRequest 异常。

如果返回的结果是 Response, 该 response 会被在链中的其他中间件的 process_response() 方法处理。

如果的结果是 Request 对象,则中间件链停止,request 会被重新调度下载。

raise IgnoreRequest 异常: 抛出异常,然后会被中间件的 process_exception() 方法会被调用。。

  • process_exception(request, exception, spider)

当下载处理器(download handler)或 process_request() (下载中间件)抛出异常(包括 IgnoreRequest 异常)时,Scrapy 调用 process_exception()。

process_exception() 的返回结果同样也是有三个: None、Response 对象、Request 对象。

如果其返回 None ,Scrapy 将会继续处理该异常,接着调用已安装的其他中间件的 process_exception() 方法,直到所有中间件都被调用完毕。

如果其返回一个 Response 对象,则其他中间件链的 process_response() 方法被调用,之后 Scrap y将不会调用其他中间件的 process_exception() 方法。

如果其返回一个 Request 对象, 则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个 response 的那样。如果 HTTP 请求失败,我们可以在这里对 HTTP 请求进行重试。例如我们频繁爬取访问一个网站导致被封 IP,就可以在这里设置增加代理继续访问。

我们可以不用实现全部方法,只需要根据需求实现对应的方法即可。例如,我想给每个 HTTP 请求都添加代理地址, 我实现 process_request() 即可。

class ProxyMiddleware(object):
    # overwrite process request
    def process_request(self, request, spider):
        # 从数据库中随机读取一个代理地址
        proxy_address = proxy_pool.random_select_proxy()
        logging.debug("=====  ProxyMiddleware get a random_proxy:【 {} 】 =====".format(proxy_address))
        request.meta['proxy'] = proxy_address
        return None

2) 在 setting.py 启用中间件 我们已经实现了中间件,最后一步需要启用该中间件。我们将定义的中间件添加到 settings.py 文件。如果你是重载系统中间件,还需要将系统的中间件的值设置为 None。我前面定义的代理中间件,是需要对 HTTP 请求做操作。所以重载了 HttpProxyMiddleware 中间件。

#  中间件填写规则
#  yourproject.myMiddlewares(文件名).middleware类

# 设置代理
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': None,
'scrapydemo.middlewares.ProxyMiddleware': 100,

原文发布于微信公众号 - 极客猴(Geek_monkey)

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

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏about云

Hadoop3.0扩展Yarn资源模型详解2:资源Profiles说明

问题导读 1.Resource profiles解决了什么问题? 2.使用profile的好处是什么? 3.配置文件的简洁模式如何配置? 上一篇hado...

49980
来自专栏简书专栏

分布式爬虫scrapy+redis入门

利用分布式爬虫scrapy+redis爬取伯乐在线网站,网站网址:http://blog.jobbole.com/all-posts/ 后文中详情写了整个工程...

51710
来自专栏zhisheng

Python爬虫入门四之Urllib库的高级用法

1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Hea...

358130
来自专栏CaiRui

Python 文件和异常

一、从文件中读取数据 #!/usr/bin/env python with open('pi') as file_object: contents =...

216100

使用Scrapy从HTML标签中提取数据

Scrapy是一个用于创建Web爬虫应用的Python框架。它提供了相关编程接口,可以通过识别新链接来抓取Web数据,并可以从下载的内容中提取结构化数据。

1.8K20
来自专栏Java帮帮-微信公众号-技术文章全总结

集群间如何实现session共享【面试+工作】

4K80
来自专栏云计算教程系列

如何在Debian 9上使用mod_rewrite为Apache重写URL

Apache的mod_rewrite模块允许您以更干净的方式重写URL,将人类可读的路径转换为代码友好的查询字符串。它还允许您根据条件重写URL。

17940
来自专栏流柯技术学院

linux下MySQL表名忽略大小写设置

最近公司项目的MySQL数据库要迁移到linux下,部署时日志总是显示报找不到一个表,用MYSQL查看明明有这个表。后来经百度,原来LINUX下的MYSQL默认...

32220
来自专栏python3

python之Windows调试

然后在代码的那个idle界面为代码添加断点,所谓断点简单的说就是调试程序时需要停顿的位置,一般在函数的入口,参数变化的行添加,这里只在fac函数入口添加一个断点...

8410
来自专栏散尽浮华

Centos7下ELK+Redis日志分析平台的集群环境部署记录

之前的文档介绍了ELK架构的基础知识(推荐参考下http://blog.oldboyedu.com/elk/),日志集中分析系统的实施方案: - ELK+Red...

33240

扫码关注云+社区

领取腾讯云代金券