Scrapy跨跳转会话认证失效,爬取需登录目录站点隔条目掉登录态
你目前的实现确实符合Scrapy官方文档的基础登录流程,但日志中暴露了两个核心的认证态丢失原因:
1. 跨二级域的Cookie隔离
登录成功后,你从www.example.com域拿到的有效认证Cookie是ASP.NET_SessionId=lgvbj33sbnlbsyp4hpe5jhxf,这个Cookie的作用范围被严格限制在www.example.com域下。
你的目录条目链接指向不带www的example.com域,Scrapy默认的Cookie中间件会遵循浏览器同源规则,不会自动把www.example.com的Cookie发送给不带www的同顶级域站点。
从日志可以看到直接的验证证据:
[scrapy.downloadermiddlewares.cookies] DEBUG: Received cookies from: <200 https://example.com/directory/members/123640> Set-Cookie: ASP.NET_SessionId=iyeclhcbqwxbfycplifedyxu; path=/; HttpOnly; SameSite=Lax
这是服务器给完全未携带登录Cookie的匿名访客下发的全新会话标识,证明服务器根本没识别到你之前的登录状态。
2. SSO跳转流程的Cookie不同步
站点采用的是跨域SSO认证逻辑,需要经过主站登录→SSO服务校验→认证Cookie同步到所有关联二级域的完整流程,才能保持跨域访问的认证态。
你目前的流程是主站登录完成后,直接跳到不带www的目录站,跳过了SSO服务的校验步骤,导致所有二级域的Cookie没有完成同步,访问任意跨域条目时都会触发登录态校验失败。
从日志可以看到请求SSO服务时的Cookie拼接混乱问题:
[scrapy.downloadermiddlewares.cookies] DEBUG: Sending cookies to: <GET https://webservice.example.com/wcasso/SsoV1/CheckLoggedIn?otherParams> Cookie: ASP.NET_SessionId=c2e3avij54xfpn4a5ofl4xdt;sso_signin=user_id=user_id_code;ASP.NET_SessionId=iyeclhcbqwxbfycplifedyxu
三个二级域的SessionId被无序拼接,SSO服务根本无法匹配到有效的登录用户身份。
1. 关闭Scrapy的域名级Cookie隔离
Scrapy默认会为每个独立域名维护独立的Cookie存储,如果你确认当前爬取的www.example.com、example.com、webservice.example.com属于同一套SSO认证体系,直接在settings.py中配置全局共享Cookie:
# 开启全局共享Cookie,所有请求共用同一份Cookie存储 COOKIES_JAR = 'shared_auth_jar'
配置后所有域的Cookie会统一存储,不再出现跨域无法携带认证信息的问题。
2. 补全SSO流程的跳转链路
在登录成功后,先主动触发SSO校验流程,等所有二级域的Cookie同步完成后,再开始抓取目录列表,对应代码调整如下:
def parse_after_login(self, response): if b"Member Section" not in response.body: self.log("Login failed") return self.log("Login success, starting SSO cookie sync") # 先请求SSO校验地址,触发全链路Cookie同步 yield scrapy.Request( url="https://webservice.example.com/wcasso/SsoV1/CheckLoggedIn", callback=self.start_crawl_directory ) def start_crawl_directory(self, response): # 跟随SSO跳转完成Cookie同步后,再开始抓取目录页 for url in PAGES: yield scrapy.Request(url, callback=self.parse_directory_page)
3. 强制携带有效认证Cookie(兜底方案)
如果调整全局Cookie后仍有跨域问题,可以写一个简单的下载中间件,在每次发起请求时强制把登录成功拿到的有效认证Cookie带上:
class ForceAuthCookieMiddleware: def process_request(self, request, spider): # 从第一次登录成功的响应中提取有效Cookie,替换无效的域专属Cookie valid_auth_cookies = { 'ASP.NET_SessionId': 'lgvbj33sbnlbsyp4hpe5jhxf', 'sso_signin': 'user_id=user_id_code' } request.cookies.update(valid_auth_cookies) return None
在settings.py中将这个中间件加入下载链路即可生效。
- 你之前配置的
CONCURRENT_REQUESTS = 1并不是解决这个问题的核心,哪怕高并发场景下,只要Cookie存储是打通的,就不会出现认证态丢失 - 你提到的
__RequestVerificationToken确实不会影响这个问题,这个参数是用于防护CSRF跨站攻击的,和长期认证态的保持没有直接关联
内容的提问来源于stack exchange,提问作者Cash

