bigywater.tech
Scrapy · 22

CookiesMiddleware:多个 cookiejar 与 meta 里的 cookiejar

爬虫登录之后为什么后面的请求会自动带 cookie?手写 Cookie 头为什么没用?多个账号要怎么隔离?这篇用一个会发 Set-Cookie 的服务器,把 CookiesMiddleware 的行为一项项量出来。

被覆盖
headers={"Cookie": …} 在默认设置下服务器收到的结果(应该用 cookies 参数)
不继承
response.follow 产生的请求带不带上一个请求的 cookiejar meta
Max-Age=1
等 2 秒后 cookie 不再发送

自动保存与发送

实测 · 本机执行输出
  COOKIES_ENABLED=1(默认):/login?u=alice 带 Cookie=(无);/other 带 Cookie=sid=alice;/me 带 Cookie=sid=alice
  COOKIES_ENABLED=0:/login?u=alice 带 Cookie=(无);/other 带 Cookie=(无);/me 带 Cookie=(无)

process_response 把 Set-Cookie 存进 cookie jar,process_request 按域名/路径等规则给请求加上 Cookie 头。

手写 Cookie 头

实测 · 本机执行输出
  /c      → 服务器收到 Cookie: via=cookies-param
  /h      → 服务器收到 Cookie: (无)
  /later  → 服务器收到 Cookie: via=cookies-param
  COOKIES_ENABLED=0:/c → (无);/h → via=header;/later → (无)

中间件在发送前会先删掉请求上已有的 Cookie 头再重建,所以要通过 Request(cookies=…) 设置,并且这些 cookie 会存进 jar,影响之后的请求。

多个 cookiejar

实测 · 本机执行输出
  /follow?jar=alice   → Cookie: (无)
  /follow?jar=bob     → Cookie: (无)
  /forgot?jar=alice   → Cookie: (无)
  /forgot?jar=bob     → Cookie: (无)
  /login?u=alice      → Cookie: (无)
  /login?u=bob        → Cookie: (无)
  /me?jar=alice       → Cookie: sid=alice
  /me?jar=bob         → Cookie: sid=bob

meta["cookiejar"] 的值是 jar 的键,不同键互不干扰;但 meta 不会自动继承,链路上的每个请求都要继续传。

作用域

实测 · 本机执行输出
  Path=/admin                         Set-Cookie: a=1; Path=/admin                → /admin/x 带 a=1;/public/x 带 (无)
  Secure(http 协议)                     Set-Cookie: a=1; Path=/; Secure             → /x 带 (无)
  Domain=localhost(请求在 127.0.0.1)     Set-Cookie: a=1; Path=/; Domain=localhost   → /x 带 (无)
  Max-Age=1:立即请求一次,等 2 秒再请求一次         Set-Cookie: a=1; Path=/; Max-Age=1          → /x 带 a=1;/x 带 (无)
  Max-Age=0(删除)                       Set-Cookie: a=1; Path=/; Max-Age=0          → /x 带 (无)
  HttpOnly + SameSite=Lax             Set-Cookie: a=1; Path=/; HttpOnly; SameSite=Lax→ /x 带 a=1

标准 cookie 规则:Path 限定路径、Secure 只在 https 发送、Domain 不匹配被拒绝、Max-Age 到期删除。

调试

实测 · 本机执行输出
  Received cookies from: <200 http://127.0.0.1:9960/login?u=alice>
    Set-Cookie: sid=alice; Path=/
  Sending cookies to: <GET http://127.0.0.1:9960/other>
    Cookie: sid=alice
  Sending cookies to: <GET http://127.0.0.1:9960/me>
    Cookie: sid=alice

COOKIES_DEBUG 打印每个收到的 Set-Cookie 和发出的 Cookie。

单个请求排除

实测 · 本机执行输出
  /login?u=carol    → Cookie: (无)
  /me1              → Cookie: (无)
  /login?u=dave     → Cookie: (无)
  /me3              → Cookie: sid=dave
  /me4              → Cookie: (无)

dont_merge_cookies 让一个请求不参与 cookie 机制:既不发也不存。

分步演示

Cookie
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。服务器 /login 返回 Set-Cookie,/setc 按 query 里给的完整 Set-Cookie 值设置,并记录每个请求收到的 Cookie 头;并发 1
    • 没有验证:公共后缀域名(如 .com)cookie 的拒绝规则(源码里有 tldextract 判断,本机没有真实域名可测);子域名之间的 cookie 共享;大量 cookie(超过 4 KB)的行为;cookie 值里的特殊字符编码;COOKIES_ENABLED 与重定向跨域的组合(重定向那一篇只测了 Cookie 头)
    京ICP备2026067502号-1京公网安备11010502063487号