关于scrapy模块中间件的简单理解

摘要

Scrapy爬虫模块是爬虫程序员使用最多的一个模块,它以快速,高层次等优势,深受爬虫工作者的喜爱,其中Scrapy的中间件功能也极其重要。中间件处于引擎和爬虫之间的钩子框架,允许开发者自定义处理请求和响应的过程。常用于用户代理,重试机制,请求头等。、

钩子框架

钩子框架是一种软件设计模式,允许程序在特定的点(钩子点)插入自定义代码。通过这些钩子点,开发者可以在不修改核心的代码的前提下扩展或修改程序的行为。(像不像python 中的装饰器)!钩子框架在插件系统,事件处理,拦截器等场景中非常常见。

在Scrapy模块中主要可以将中间件分为两类:

下载器中间件(Downloader Middleware): 处理请求和响应,与下载器交互。

爬虫中间件(Spider Middleware): 处理从下载器传递到爬虫的响应以及从爬虫输出的请求。

下载器中间件:

在下载器中间件(Downloader Middleware)中主要有以下方法:

process_request(request, spider)

process_request(request, spider): 在请求发送到下载器之前调用。基于这个原理,我们可以自定义头部,cookie, 代理ip,用户认证等信息添加上

1,添加自定义头部信息

为每一个请求添加一个自定义的头部信息

 def process_request(self, request, spider):# 在请求发送之前添加一个自定义头部request.headers['X-Custom-Header'] = 'CustomValue'return None

2, 设置代理

为请求设置代理服务器

class ProxyMiddleware:def process_request(self, request, spider):request.meta['proxy'] = "http://your_proxy_server:port"return None

3,模拟用户登录(cookie)

在请求中添加cookie模拟用户登录

class LoginMiddleware:def process_request(self, request, spider):request.cookies['sessionid'] = 'your_session_id'return None

4, 返回缓存响应

如果需要,可以直接返回一个缓存的响应,而不发送实际请求

from scrapy.http import HtmlResponseclass CacheMiddleware:def process_request(self, request, spider):if some_condition_based_on_request(request):return HtmlResponse(url=request.url, body='Cached response', encoding='utf-8', request=request)return None

启用中间件

要使中间件生效,需要在settings.py中启用它

process_response(request, response, spider)

process_response(request, response, spider):用于在下载器接收到响应后进行处理。通过这个方法,我们可以修改响应对象,执行日志记录,处理错误操作

方法签名

def process_response(self, request, response, spider):# 这里编写处理逻辑return response  # 或返回一个新的 Response 对象,或者抛出一个 IgnoreRequest 异常

参数说明

request :scrapy.http.Request对象,表示对应的请求

response:scrapy.http.Response对象,表示下载器接收到的响应

spider:当前处理响应的爬虫实例,便于访问爬虫的属性方法

返回值

response对象:可以使传入的响应对象,也可以是一个新的响应对象。如果返回新的响应对象,那么原有的响应将被替换。

request对象:可以返回一个新的请求对象,重新调度新的请求。

IgnoreRequest异常:可以抛出scrapy.exceptions.IgnoreRequest异常,忽略该请求

1,修改响应内容

可以对响应的内容进行修改,例如添加自定义标记或替换某些内容(例如给爬取的数据加上时间戳)

class ModifyResponseMiddleware:def process_response(self, request, response, spider):# 假设我们希望在响应体中添加一个自定义标记modified_body = response.body + b'\n<!-- Custom Footer -->'return response.replace(body=modified_body)

2, 日志记录

记录响应的状态码,方便调试和监控:

class LogResponseMiddleware:def process_response(self, request, response, spider):spider.logger.info(f'Response received from {request.url} with status {response.status}')return response

3,重试处理

根据响应状态码决定是否进行重试,例如对于某些特定的错误状态码进行重试:

from scrapy.exceptions import IgnoreRequestclass RetryMiddleware:def process_response(self, request, response, spider):if response.status in [500, 502, 503, 504]:spider.logger.warning(f'Retrying {request.url} due to server error {response.status}')return request  # 重新调度请求以进行重试return response

4, 缓存响应

将响应缓存到本地文件,避免重复下载:

import os
from scrapy.http import HtmlResponseclass CacheResponseMiddleware:def process_response(self, request, response, spider):cache_dir = 'cache'os.makedirs(cache_dir, exist_ok=True)cache_path = os.path.join(cache_dir, f"{hash(request.url)}.html")with open(cache_path, 'wb') as f:f.write(response.body)return responsedef process_request(self, request, spider):cache_path = os.path.join('cache', f"{hash(request.url)}.html")if os.path.exists(cache_path):with open(cache_path, 'rb') as f:body = f.read()return HtmlResponse(url=request.url, body=body, encoding='utf-8', request=request)return None

最后要在setting中启用这些中间件

process_exception(request, exception, spider)

process_exception(request, exception, spider):用于处理在爬取过程中发生的异常,当请求处理过程中出现异常时,Scrapy将调用该方法,并将相关请求,异常和爬虫对象作为参数传递给该方法。

参数说明

request:发生异常的请求对象

exception: 抛出的异常对象

spider: 当前爬虫对象

使用process_exception()方法可以根据具体的需求来处理异常,记录日志,重新发送请求,忽略异常等,以下是一个代码示例:

class MyMiddleware(object):def process_exception(self, request, exception, spider):# 处理异常的逻辑print(f"An exception occurred while processing {request.url}: {exception}")# 返回None表示继续处理异常,返回Response对象表示忽略异常并返回自定义的响应return None

在这个示例中,我们打印了异常的详细信息,并返回了None,表示继续处理异常。如果要忽略异常并返回自定义响应,可以通过返回一个Response对象来实现。

爬虫中间件:

爬虫中间件主要包括以下方法:

  • process_spider_input(response, spider):在爬虫处理响应之前调用。
  • process_spider_output(response, result, spider):在爬虫处理完响应之后调用。
  • process_spider_exception(response, exception, spider):在爬虫处理响应过程中抛出异常时调用。
  • process_start_requests(start_requests, spider):处理爬虫产生的初始请求。

我们一一介绍

process_spider_input(response, spider):

process_spider_input(response, spider)用于在爬虫处理响应数据之前对响应进行预处理。这个方法通常被用来对响应进行一些定制化的操作,例如修改响应内容,添加额外的字段或者进行其他预处理操作。

当爬虫处理一个响应时,scrapy会调用每个下载中间件的process_spider_input()方法,以便对响应进行处理,这个方法可以在自定义的下载中间件中实现,来响应进行定制化处理。

以下是process_spider_input()方法的参数说明:

response:要处理的响应对象。

spider:当前爬虫对象

如何在自定义下载中间件中实现process_spider_input()方法:

class MyMiddleware(object):def process_spider_input(self, response, spider):# 对响应进行处理的逻辑if 'special_field' not in response.meta:response.meta['special_field'] = 'special_value'return response

在这个实例中,在process_spider_input()方法中向响应的meta信息中添加一个特使字段,如果这个字段不存在的话。然后返回了处理后的响应对象。这样在爬虫处理响应数据之前,我们就可以对响应进行一些自定义的操作。

process_spider_output(response, result, spider)

process_spider_output(response, result, spider) :用于在爬虫生成的结果(如item, Request等)返回之前对其进行处理。这个方法通常被用在自定义的爬虫中间件中,以便对爬虫生成的结果进行筛选,修改或扩展。

该方法在爬虫处理完一个响应后,生成结果会依次传递给每个爬虫中间件的process_spider_output()方法,这样就可以在结果返回给引擎之情对其进行处理。

以下是process_spider_output()方法的参数说明:

response:处理过的响应对象

result:爬虫返回的结果,通常是包含一个item,request或者其他对象的可迭代对象(如生成器,列表等)

spider:当前爬虫对象。

下面一个简单的代码,展示如何在自定义爬虫中间件中实现process_spider_output方法:

class MySpiderMiddleware(object):def process_spider_output(self, response, result, spider):# 对爬虫输出的结果进行处理的逻辑for item in result:if isinstance(item, dict):  # 假设我们只对Item进行处理item['processed_by'] = 'MySpiderMiddleware'yield item

在这个实例中,process_spider_output()方法逐一处理爬虫生成的结果。如果结果是一个字典(假设它是一个item),则在其中添加一个字段processed_by,然后再将结果通过yield返回,这种方式可以确保所有生成的结果都被处理返回。

需要注意的是,process_spider_output()方法应该返回一个可迭代对象(通常使用yield来逐个返回结果)。如果多个中间件实现这个方法,它们将在设置中的顺序依次被调用,对结果进行链式处理。记得在中间件中启用。

process_spider_exception(response, exception, spider)

process_spider_exception(response, exception, spider):用于爬虫处理响应时发生异常时,对该异常进行处理。这个方法通常被用在自定义的爬虫中间件中,以便在异常发生时执行特定的逻辑,例如日志记录,错误处理或重试等操作。

方法参数:

response:导致异常的响应对象

exception:抛出的异常对象

spider:当前的爬虫对象

返回值

可以返回None或者一个None值的可迭代对象以继续传播异常或者可以返回一个新的result(如Item或Request对象)的可迭代对象在替代异常。

class MySpiderMiddleware(object):def process_spider_exception(self, response, exception, spider):# 处理异常的逻辑spider.logger.error(f"Exception caught: {exception} for URL: {response.url}")# 如果需要,可以生成新的Request以重试请求if isinstance(exception, SomeSpecificException):new_request = response.request.copy()new_request.dont_filter = True  # 不要因为重复请求而被过滤return [new_request]# 返回None以继续传播异常return None

在这个实例中,当爬虫处理响应时发生异常时,process_spider_exception()方法会:

1,记录异常信息和相关的URL

2, 如果异常类型为SomeSpecificException,则生成一个新的请求以重试该请求,并返回这个请求。

3,如果不是这个特定的异常类型,则返回None,继续传播异常

为了让Scrapy使用这个中间件,需要在项目的设置文件settings.py中启用它

process_start_requests(start_requests, spider)

process_start_requests(start_requests, spider): 用于在开始爬取时对起始请求进行处理。这个方法通常被用在自定义的爬虫中间件中,以便对起始请求进行自定义操作,例如添加额外的请求参数,修改请求头部。这和下载器中间件的process_request(request, spider)方法类似。

方法参数

start_requests:起始请求的可迭代对象。

spider:当前的爬虫对象

返回值

必须返回一个可迭代对象,该对象包含要发送的起始请求。

下面是一个示例代码,展示了如何在自定义爬虫中间件中实现process_start_requests()方法

class MySpiderMiddleware(object):def process_start_requests(self, start_requests, spider):# 对起始请求进行处理的逻辑for request in start_requests:# 添加额外的请求参数request.meta['extra_param'] = 'some_value'# 修改请求头部request.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'yield request

在这个示例中,process_start_request()方法会遍历起始请求,并对每个请求执行以下操作:

1,添加名为extra_param的额外参数请求,值为“some_value”

2,修改请求的头部,将User_Agent修改为指定的值

3,通过yield返回修改请求。

记得在settings.py文件汇总启用它

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/854660.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

富格林:需知k线阻挠交易欺诈

富格林指出&#xff0c;尽管现货黄金的投资机会十分充足&#xff0c;但也并不代表能够轻松获得盈利。尤其是近段时间行情较多&#xff0c;做单的难度无疑也会有所提升&#xff0c;所以要想阻挠交易欺诈在黄金市场当中盈利&#xff0c;就得学会分析现货黄金K线图。下面富格林将总…

Linux网络 - HTTP协议

文章目录 前言一、HTTP协议1.urlurl特殊字符 requestrespond 总结 前言 上一章内容我们讲了在应用层制定了我们自己自定义的协议、序列化和反序列化。 协议的制定相对来讲还是比较麻烦的&#xff0c;不过既然应用层的协议制定是必要的&#xff0c;那么肯定已经有许多计算机大佬…

C++使用spdlog输出日志文件

参考博客&#xff1a; 日志记录库 spdlog 基础使用_spdlog 写日志-CSDN博客 GitHub - gabime/spdlog: Fast C logging library. 首先在github上下载spdlog源码&#xff0c;不想编译成库的话&#xff0c;可以直接使用源码&#xff0c;将include文件夹下的spdlog文件夹&#x…

网络:用2个IP地址描述一个连接

用2个IP地址描述一个连接。这是在阅读了《TCP/IP指南》后的感想&#xff0c;与工业标准不同&#xff0c;需注意区分。 如果一个IP地址有48位&#xff0c;则用96位描述一个连接 对于单播&#xff0c;是每个IP分别描述位置。位置包括&#xff1a;邮局编号主机编号&#xff0c;采用…

Qt 信号与槽机制概述

在 Qt 中&#xff0c;emit 是一个用于发射信号的关键字。它是 Qt 的信号与槽&#xff08;Signals and Slots&#xff09;机制的一部分&#xff0c;用于在某个条件满足时通知其他对象。发射信号是一种实现对象之间通信的方式&#xff0c;特别是在事件驱动编程模型中。 Qt 信号与…

示例:WPF中TreeView自定义TreeNode泛型绑定对象

一、目的&#xff1a;在开发中经常需要绑定TreeView&#xff0c;所以定义了一个泛型的TreeNode<T>用来方便绑定对象和复用 二、实现 public partial class TreeNodeBase<T> : SelectBindable<T>, ITreeNode{public TreeNodeBase(T t) : base(t){}private Obs…

MySQL常见的命令

MySQL常见的命令 查看数据库&#xff08;注意添加分号&#xff09; show databases;进入到某个库 use 库; 例如&#xff1a;进入test use test;显示表格 show tables;直接展示某个库里面的表 show tables from 库&#xff1b; 例如&#xff1a;展示mysql中的表格 show tabl…

前端三大件速成 05 javascript(2)字符串对象、数组对象、函数对象、BOM对象、DOM对象

文章目录 一、字符串对象1、创建字符串对象的两种方式2、字符串属性3、字符串的方法&#xff08;1&#xff09;编排方法&#xff08;2&#xff09;查询字符串索引&#xff08;3&#xff09;字符串切片&#xff08;4&#xff09;大小写转换&#xff08;5&#xff09;获取指定字符…

Python网络数据抓取(9):XPath

引言 XPath 是一种用于从 XML 文档中选取特定节点的查询语言。如果你对 XML 文档不太熟悉&#xff0c;XPath 可以帮你完成网页抓取的所有工作。 实战 XML&#xff0c;即扩展标记语言&#xff0c;它与 HTML&#xff0c;也就是我们熟知的超文本标记语言&#xff0c;有相似之处&am…

python脚本之解析命令参数

import requests import argparseprint(f"{__name__}:start")parser argparse.ArgumentParser(description使用方法) parser.add_argument(-p, --prefix, typestr, help域名) parser.add_argument(-t, --token, typestr, helptoken) parser.add_argument(-i, --queu…

pyqt 鼠绘椭圆 椭圆标注

目录 pyqt 椭圆标注 四个方向可以调整,调整时,另一端固定,只调整当前端,椭圆参数保存加载json pyqt 画椭圆中心点固定,调整是,两端一起调整。 pyqt 椭圆标注 四个方向可以调整,调整时,另一端固定,只调整当前端,椭圆参数保存加载json import sys import json from …

ClickHouse快速安装教程(MacOS)

文章目录 ClickHouse快速安装教程&#xff08;MacOS&#xff09;1.ClickHouse2.快速安装3.快速启动3.1.启动服务器3.2.启动客户端 4.使用案例1.配置文件2.启动CK服务3.创建数据库4.创建表5.插入数据6.查询数据 ClickHouse快速安装教程&#xff08;MacOS&#xff09; 1.ClickHo…

前端开发之HTTP协议

上一篇&#x1f449;: 前端开发之WebSocket通信 文章目录 1. HTTP 1.0 和 HTTP 1.1 之间有哪些区别1.连接方面&#xff1a;2.资源传输优化&#xff1a;3.缓存机制增强&#xff1a;4.主机头识别5.请求方法扩展 2.HTTP 1.1 和 HTTP 2.0 的区别1. 二进制分帧层&#xff1a;2.多路…

【UEditorPlus】后端配置项没有正常加载,上传插件不能正常使用

接上文【UEditorPlus】后端配置项没有正常加载&#xff0c;上传插件不能正常使用_ueditor ruoyi vue后端配置项没有正常加载,上传插件不能正常使用!-CSDN博客 成功解决图片、视频上传问题后&#xff0c;当服务部署在公网时&#xff0c;会存在大文件无法正常上传的问题。 出现…

makefile中连接使用-lssh2 连接命令提示找不到lssh2 解决

一&#xff1a; 第一种方式自己下载源码编译生成.so 库 安装libssh2之前需要先安装openssl&#xff0c;否则将导致libssh2无法安装 openssl 的下载地址: https://www.openssl.org/source/ libssh2下载地址&#xff1a; https://www.libssh2.org/download/ openssl 的下载…

C# range

基本概念索引范围前缀和后缀范围完整范围示例用法访问数组的子集使用范围进行迭代使用范围进行切片生成一个范围的整数序列步进范围使用范围表达式进行条件过滤 注意事项 在 C# 8.0 及以上版本中&#xff0c;引入了一种新的语法特性&#xff0c;称为“范围”&#xff08; ran…

电感的本质是什么

什么是电感&#xff1f; 电感器件一般是指螺线圈&#xff0c;由导线圈一圈靠一圈地绕在绝缘管上&#xff0c;绝缘管可以是空心的&#xff0c;也可以包含铁芯或磁粉芯。 为什么把’线’绕成’圈’就是电感&#xff1f; 电感的工作原理非常抽象&#xff0c;为了解释什么是电感…

Python写一个MES系统和ERP系统协同任务流程

在这个示例中&#xff0c;我将向您展示如何使用Python编写一个简单的MES&#xff08;制造执行系统&#xff09;和ERP&#xff08;企业资源规划系统&#xff09;协同任务流程。我们将通过一个简单的示例来展示这两个系统如何协同工作。 首先&#xff0c;我们需要了解MES和ERP系统…

游戏服务器要注意哪些安全事项?

网络安全对于游戏行业来说是至关重要的&#xff0c;当游戏行业受到恶意的攻击者进行网络攻击时&#xff0c;严重的会导致服务器崩溃&#xff0c;使业务无法正常进行工作运行&#xff0c;给企业造成巨大的经济损失&#xff0c;那么对于网络安全&#xff0c;游戏服务器需要注意哪…

04通讯录管理系统——退出功能实现

功能描述&#xff1a;退出通讯录 思路&#xff1a;根据用户不同的选项&#xff0c;进入不同的功能&#xff0c;可以选择switch分支结构&#xff0c;将整个架构进行搭建 当用户选择0时&#xff0c;执行退出&#xff0c;选择其他时先不做操作&#xff0c;也不退出程序 代码&am…