bigywater.tech
Scrapy · 24

默认请求头与 User-Agent 的设置位置

默认请求头从哪来?设置、请求、spider 里都能写 User-Agent,谁最终生效?发出的头是什么顺序和大小写?这篇用原始套接字服务器看真正出现在网络上的字节。

5 个
默认 GET 请求的头:Accept、Accept-Language、User-Agent、Accept-Encoding、Host
gzip, deflate, br, zstd
默认的 Accept-Encoding(压缩中间件写死)
0 个
USER_AGENT 设成空串时发出的 User-Agent 头

三个来源

实测 · 本机执行输出
  GET 请求:
    GET /a HTTP/1.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en
    User-Agent: Scrapy/2.19.0 (+https://scrapy.org)
    Accept-Encoding: gzip, deflate, br, zstd
    Host: 127.0.0.1:端口

DefaultHeadersMiddleware(DEFAULT_REQUEST_HEADERS)、UserAgentMiddleware(USER_AGENT)和 HttpCompressionMiddleware(Accept-Encoding)各自用 setdefault 补头;请求自己的头永远优先。

默认值

实测 · 本机执行输出
  USER_AGENT = Scrapy/2.19.0 (+https://scrapy.org)
  DEFAULT_REQUEST_HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en'}

Accept 和 Accept-Language 在 DEFAULT_REQUEST_HEADERS 里,USER_AGENT 带着版本号;Accept-Encoding 不在设置里。

覆盖规则

实测 · 本机执行输出
  只改 USER_AGENT 设置:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en
      User-Agent: MyBot/1.0
      Accept-Encoding: gzip, deflate, br, zstd
  Request 的 headers 里写 User-Agent:
      User-Agent: PerRequest/9
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en
      Accept-Encoding: gzip, deflate, br, zstd
  DEFAULT_REQUEST_HEADERS 改 Accept-Language,新增 X-Token:
      Accept: application/json
      Accept-Language: zh-CN
      X-Token: t
      User-Agent: Scrapy/2.19.0 (+https://scrapy.org)
      Accept-Encoding: gzip, deflate, br, zstd
  Request 的 headers 覆盖 Accept-Language:
      Accept-Language: fr
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      User-Agent: Scrapy/2.19.0 (+https://scrapy.org)
      Accept-Encoding: gzip, deflate, br, zstd
  USER_AGENT 设成空串:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en
      Accept-Encoding: gzip, deflate, br, zstd
      (没有 User-Agent 头)
  COMPRESSION_ENABLED=0:
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en
      User-Agent: Scrapy/2.19.0 (+https://scrapy.org)

替换 DEFAULT_REQUEST_HEADERS 是整体替换;把 USER_AGENT 设空串则不发这个头;关闭压缩中间件则不发 Accept-Encoding。

头名与多值

实测 · 本机执行输出
    GET /a HTTP/1.1
    User-Agent: lower
    Accept: UPPER
    X-Custom-Header: v
    X-Multi: a
    X-Multi: b
    Accept-Language: en
    Accept-Encoding: gzip, deflate, br, zstd
    Host: 127.0.0.1:端口

头名在发出前规范成首字母大写,值是列表时拆成多行。

POST 与表单

实测 · 本机执行输出
    POST /p HTTP/1.1
    Content-Length: 7
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en
    User-Agent: Scrapy/2.19.0 (+https://scrapy.org)
    Accept-Encoding: gzip, deflate, br, zstd
    Host: 127.0.0.1:端口
    
    a=1&b=2
  FormRequest(formdata=…):
    POST /p HTTP/1.1
    Content-Length: 7
    Content-Type: application/x-www-form-urlencoded
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en
    User-Agent: Scrapy/2.19.0 (+https://scrapy.org)
    Accept-Encoding: gzip, deflate, br, zstd
    Host: 127.0.0.1:端口
    
    a=1&b=2

手写 POST 的 Request 只有 Content-Length;FormRequest 会加上表单的 Content-Type。

分步演示

请求头
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Scrapy 2.19.0 / Twisted 26.4.0 / lxml 6.1.3 / parsel 1.12.1(临时虚拟环境);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、重定向、压缩、断连等行为,并记录收到的原始请求;每个实验在临时目录里新建 Scrapy 项目或单文件 spider,命令输出来自真实的 scrapy 进程;计时用 time.perf_counter,数字每次运行会有小幅抖动。用 RawSrv(原始套接字服务器)读取并原样记录请求头块;每个情形是一个单文件 spider
    • 没有验证:HTTPS 请求的头(ALPN、TLS 层之外的头相同,但没有抓包);HTTP/2 处理器发出的头(见后面的文章);aiohttp 处理器(无 reactor 模式)是否改变头的顺序和 Connection 头;spider 的 user_agent 属性(2.19 里已弃用,没有再测);Cookie、Referer、Authorization 等由别的中间件添加的头(见 cookies、重定向篇)
    京ICP备2026067502号-1京公网安备11010502063487号