Scrapy多账号需禁用默认CookiesMiddleware并自定义CookiePoolMiddleware实现账号隔离、自动轮换与失效检测,登录必须与Cookie池强绑定实时更新。

Scrapy里直接用cookies参数根本撑不住多账号场景
Scrapy的Request支持cookies参数,但这是单次请求级的硬编码——每次发请求都得手动传字典,账号一多就变成重复造轮子。更麻烦的是,登录态过期、账号被限流、Cookie失效后没法自动切换或刷新,爬虫会卡死在某个账号上,连日志都难定位是哪个账号挂了。
真正可行的做法是把Cookie当成可调度的资源来管理,而不是静态配置。核心思路:用独立模块维护账号生命周期,让Downloader Middleware接管请求时的Cookie注入逻辑。
用scrapy.downloadermiddlewares.cookies.CookiesMiddleware之前先关掉它
Scrapy默认启用CookiesMiddleware,它会自动提取响应里的Set-Cookie并回填到后续请求,这和你手动维护的多账号Cookie池冲突——它会把不同账号的Cookie混在一起塞进同一个CookieJar,导致账号污染甚至403。
必须在settings.py里显式禁用:
立即学习“Python免费学习笔记(深入)”;
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': None,
}
否则哪怕你写了再漂亮的Cookie池,也会被默认中间件悄悄覆盖掉。
自定义CookiePoolMiddleware实现账号隔离与自动轮换
中间件要解决三个实际问题:从池中取可用账号、把对应Cookie注入Request.headers['Cookie']、检测响应是否失效(比如返回登录页HTML或401)并标记该账号待刷新。
- 账号信息建议存在Redis里,字段至少包含
account_id、cookies_dict(JSON序列化)、last_used_at、status(active/expired/locked) - 每次
process_request时用Lua脚本原子性地取一个status == active的账号,并更新last_used_at - 别直接拼
Cookie: key1=value1; key2=value2,用http.cookies.SimpleCookie构造再转字符串,避免特殊字符(如空格、分号)引发服务端解析失败 - 在
process_response里检查response.status和b'login' in response.body等信号,触发mark_as_expired(account_id)
登录动作必须和Cookie池更新强绑定,不能靠定时任务补漏
很多团队用单独脚本定期重登账号,写入Redis——这会造成时间窗口内爬虫拿到的是旧Cookie,而登录脚本还没写完新值,结果大量请求带着过期凭证发出去,触发风控。
正确做法是在中间件检测到失效后,立即调用同步登录函数(比如封装好的relogin(account_id)),成功后再把新cookies_dict写回Redis,并重试原请求。注意:relogin必须是阻塞式、带重试和验证码处理的完整流程,不能只POST登录接口就完事。
这个环节最容易被跳过:有人以为“反正有备用账号”,结果所有账号因未及时刷新Cookie,在几小时内集体失效,爬虫流量突然归零——而日志里只显示一堆401,看不出根源是Cookie没更新。


















