ASP.NET分页爬取重复问题:Scrapy去重失效该如何解决?
解决Scrapy爬取ASP.NET站点时URL相同导致的无限循环问题
嗨,这个问题我太熟悉了!ASP.NET站点依赖__VIEWSTATE、__EVENTTARGET这类表单参数来区分不同请求,而Scrapy默认的去重逻辑只看URL,再加上你代码里用了dont_filter=True直接跳过检查,自然会陷入无限循环。给你几个实用的解决方案:
1. 自定义DupeFilter,基于URL+表单参数组合去重
这是最规范的做法,能让Scrapy的去重机制适配ASP.NET的请求特点。你可以继承Scrapy自带的RFPDupeFilter,重写指纹生成逻辑,把表单里的关键参数(比如__EVENTTARGET、__VIEWSTATE)加入指纹计算:
from scrapy.dupefilters import RFPDupeFilter from scrapy.utils.request import request_fingerprint class ASPNetDupeFilter(RFPDupeFilter): def request_fingerprint(self, request): # 获取请求的表单数据(FormRequest才会有) form_data = request.formdata or {} # 先生成默认的URL指纹,再拼接排序后的表单参数,确保参数顺序不影响指纹 base_fp = request_fingerprint(request) custom_fp = base_fp + str(sorted(form_data.items())).encode('utf-8') return custom_fp
然后在你的项目settings.py里配置使用这个自定义去重器:
DUPEFILTER_CLASS = '你的项目名.dupefilters.ASPNetDupeFilter' # 替换成实际路径
2. 移除dont_filter=True
你代码里加了这个参数,会让Scrapy完全跳过所有去重检查,这是导致无限循环的直接原因之一。除非你有特殊的跳过需求,否则一定要删掉这个参数,让自定义的DupeFilter发挥作用。
3. 手动跟踪已请求的关键参数(简单场景首选)
如果你的爬虫逻辑比较简单,不想自定义DupeFilter,也可以在爬虫类里维护一个集合,记录已经发送过的__EVENTTARGET值,生成请求前先做检查:
class YourAspSpider(scrapy.Spider): name = 'asp_net_spider' # 用集合存储已访问过的__EVENTTARGET值,保证查询效率 visited_event_targets = set() def parse(self, response): if '1' in page: # 注意确保page变量已正确定义 target_links = response.xpath("//a[@class = 'dtgNormalPage']").extract()[1:] for link in target_links: event_target = link.split("'")[1].replace('$', ':') # 检查这个参数是否已经请求过 if event_target not in self.visited_event_targets: self.visited_event_targets.add(event_target) yield FormRequest.from_response( response, url, callback=self.pages, formdata={'__EVENTTARGET': event_target} # 去掉dont_filter=True! )
这种方法简单直接,不需要修改全局配置,适合小规模的ASP.NET站点爬取。
额外提示
ASP.NET站点的__VIEWSTATE和__VIEWSTATEGENERATOR也是动态变化的,每次请求后都要从响应里提取最新的值,放到下一次请求的formdata里,否则可能会请求失败或者被判定为重复提交。
内容的提问来源于stack exchange,提问作者JBJ
相关产品推荐
相关产品推荐

