Scrapy中ASP.NET会话ID过期后如何获取新会话ID?
解决Scrapy爬虫中ASP.NET会话ID过期无法重置的问题
你已经精准定位到了核心问题——会话ID过期后,Scrapy仍在复用旧的Cookie,导致站点返回空白内容;而重启爬虫清空CookieJar后,就能拿到新会话正常爬取。下面给你具体的解决方案和诊断思路:
一、手动清除ASP.NET_SessionId Cookie,强制获取新会话
当检测到页面返回空白(len(rows) < 50)时,需要在重新提交表单的请求中主动清除旧的ASP.NET_SessionId Cookie,让站点认为是新访问并颁发新会话ID。
修改你parse_index方法里的重试逻辑:
if (len(rows) < 50 and self.count != self.numberOfPages): self.log('Deficient rows. Resubmitting with fresh session') # 两种方式强制获取新会话:二选一即可 # 方式1:手动清空ASP.NET_SessionId Cookie yield scrapy.FormRequest( url=self.base_url, formdata={'id':'frmSearch', 'SearchField':'%','cmdGo':'Go'}, callback=self.parse_index, cookies={'ASP.NET_SessionId': ''} # 覆盖旧会话ID ) # 方式2:禁用当前请求复用已有Cookie,强制站点返回新会话 # yield scrapy.FormRequest( # url=self.base_url, # formdata={'id':'frmSearch', 'SearchField':'%','cmdGo':'Go'}, # callback=self.parse_index, # meta={'dont_merge_cookies': True} # )
二、彻底重置Scrapy的CookieJar
如果上面的方法无效,可以直接操作爬虫的CookieJar清空所有Cookie,再重新发起请求:
from scrapy.http.cookies import CookieJar def start_requests(self): # 初始化CookieJar并传递到请求meta中 cookie_jar = CookieJar() yield scrapy.Request( url=self.start_urls[0], callback=self.parse, meta={'cookie_jar': cookie_jar} ) def parse_index(self, response): self.log('proceeding to next page') rows = response.css(self.rows_selector) if (len(rows) < 50 and self.count != self.numberOfPages): self.log('Deficient rows. Resetting entire cookie jar') # 获取当前CookieJar并清空 cookie_jar = response.meta.get('cookie_jar') if cookie_jar: cookie_jar.clear() # 重新提交表单获取新会话 yield scrapy.FormRequest( url=self.base_url, formdata={'id':'frmSearch', 'SearchField':'%','cmdGo':'Go'}, callback=self.parse_index, meta={'cookie_jar': cookie_jar} )
三、诊断Scrapy是否接收新会话ID
你提到站点应该在会话过期后颁发新ID,但Scrapy没接收,可以通过以下方式排查:
- 开启DEBUG日志:在
settings.py中设置LOG_LEVEL = 'DEBUG',Scrapy会打印所有Cookie的收发细节,你可以查看是否有Set-Cookie: ASP.NET_SessionId=xxx的响应头,以及Scrapy是否保存了这个新Cookie。 - 打印响应头:在
parse_index里添加一行代码,直观查看站点是否返回新会话ID:self.log(f"Response Set-Cookie: {response.headers.get('Set-Cookie')}") - 对比抓包请求:用Fiddler对比手动重启爬虫时的请求和自动重试时的请求,除了会话ID外,检查请求头、表单参数是否有差异,有些ASP.NET站点会要求特定参数触发新会话。
四、优化续爬逻辑(可选)
可以把当前爬取的页码count保存到本地文件,避免手动修改代码续爬:
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 初始化时读取上次的爬取页码 try: with open('last_page.txt', 'r') as f: self.count = int(f.read().strip()) except FileNotFoundError: self.count = 1 def parse_index(self, response): # ... 你的爬取逻辑 ... if self.count <= self.numberOfPages: # 每次爬完一页保存当前页码 with open('last_page.txt', 'w') as f: f.write(str(self.count)) yield scrapy.Request( callback=self.parse_index, url=self.base_url + '?page=' + str(self.count) )
内容的提问来源于stack exchange,提问作者kotval
相关产品推荐
相关产品推荐

