You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy:如何实现中间件向爬虫本体传递捕获的请求数据

实现方案

完全可以通过自定义下载中间件实现原始请求头、请求体的捕获,这种方式拿到的是请求实际发出前的原始数据,比从response.request上取的准确性更高,不会被请求发送后的中间件处理逻辑篡改。

核心实现逻辑

  • 选择下载中间件的process_request方法作为捕获点:这个方法执行时请求还未发送到网络,此时拿到的request.headers、request.body就是最终发出的原始请求头和请求payload,不会经过响应阶段的逻辑修改。
  • 捕获后的数据通过request.meta传递即可,传递前注意把headers、body这类特殊类型转成常规可序列化格式,方便后续存库或者解析。
  • 不要在捕获逻辑里修改请求本身的属性,避免影响正常请求发送。

中间件代码示例

from scrapy import Request
import json
from urllib.parse import parse_qs

class RawRequestCaptureMiddleware:
    def process_request(self, request, spider):
        # 转换原始请求头为普通字典,统一处理字节编码
        raw_headers = {}
        for key, value in request.headers.items():
            raw_headers[key.decode("utf-8")] = value.decode("utf-8")
        
        # 捕获原始请求体,兼容不同请求格式做可读化解析
        raw_body = request.body
        raw_body_parsed = raw_body
        content_type = raw_headers.get("Content-Type", "")
        try:
            if "application/json" in content_type:
                raw_body_parsed = json.loads(raw_body.decode("utf-8"))
            elif "application/x-www-form-urlencoded" in content_type:
                raw_body_parsed = {k: v[0] if len(v) ==1 else v for k,v in parse_qs(raw_body.decode("utf-8")).items()}
            else:
                raw_body_parsed = raw_body.decode("utf-8", errors="ignore")
        except:
            pass

        # 写入meta传递给后续爬虫逻辑
        request.meta["raw_request_trace"] = {
            "request_url": request.url,
            "request_method": request.method,
            "headers": raw_headers,
            "raw_body": raw_body,
            "parsed_body": raw_body_parsed
        }

        # 无返回值,让请求继续走正常发送流程
        return None

中间件配置

在项目settings.py中注册中间件,优先级调整到靠近下载器的位置,确保捕获的是最终发出的请求数据:

DOWNLOADER_MIDDLEWARES = {
    "your_project.middlewares.RawRequestCaptureMiddleware": 649,
}

优先级数值越大越靠近下载器,650是Scrapy内置HttpCompressionMiddleware的优先级,设为649可以确保在所有请求修改类中间件执行完后、请求发送前捕获数据。

爬虫侧调用方式

在爬虫的解析方法中,直接从response.meta中读取捕获的数据即可,拿到的数据可以直接用于存库追踪:

def parse(self, response):
    trace_info = response.meta.get("raw_request_trace", {})
    # 此处可直接把trace_info和爬取结果绑定存入数据库
    yield {
        "item_content": ...,
        "request_trace": trace_info
    }

注意事项

  • 遇到请求重试、重定向场景时,process_request会在每次实际发请求前重新执行,捕获到的是和当前响应直接绑定的那次请求的原始数据,完全符合追踪需求。
  • 如果存在大文件上传、大体积请求体的场景,可以在捕获逻辑里加判断,只存关键参数或者body摘要,避免meta占用过多内存。
  • 可以按需加过滤规则,比如只捕获指定域名、指定路径的请求信息,减少不必要的性能开销。

内容的提问来源于stack exchange,提问作者fobik35911

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 09:39:57