如何使用CrawlSpider和Rules对特定域名关闭去重过滤?
针对特定域名禁用Scrapy去重过滤的解决方案
你遇到的问题是特定域名的分页请求重定向回初始URL后被Scrapy的去重机制过滤,导致无法爬取。完全可以针对单个域名禁用去重,以下是几种可行的实现方式:
方法1:自定义域名专属去重中间件
继承Scrapy默认的去重中间件,对目标域名跳过去重检查:
from scrapy.downloadermiddlewares.duplicates import DuplicatesFilter from scrapy.utils.request import request_fingerprint class DomainSpecificDuplicatesFilter(DuplicatesFilter): def request_seen(self, request): # 替换成你需要禁用去重的目标域名 target_domain = 'piwi.wiesbaden.de' if target_domain in request.url: return False # 返回False表示未见过该请求,不触发去重 # 其他域名沿用默认去重逻辑 fp = request_fingerprint(request) if fp in self.fingerprints: return True self.fingerprints.add(fp) if self.file: self.file.write(fp + '\n')
在项目的settings.py中替换默认去重中间件:
DOWNLOADER_MIDDLEWARES = { '你的项目名.middlewares.DomainSpecificDuplicatesFilter': 300, 'scrapy.downloadermiddlewares.duplicates.DuplicatesFilter': None, }
方法2:在链接提取阶段添加去重豁免标记
修改LinkExtractor的process_links方法,给目标域名的链接对应的请求添加dont_filter=True参数:
from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule def process_links(links): target_domain = 'piwi.wiesbaden.de' for link in links: if target_domain in link.url: link.meta['dont_filter'] = True return links class MySpider(CrawlSpider): name = 'spdr' start_urls = [ i.strip() for i in open('list.txt', 'r').read().splitlines() if i and i.strip() ] rules = [ Rule( LinkExtractor( allow=[], restrict_css=[ "a[rel='next']", "a[href*='nav_top-next']", ], process_links=process_links # 启用自定义链接处理函数 ), follow=True, ), # 其他规则... ]
方法3:用请求拦截中间件豁免目标域名
编写一个简单的下载中间件,拦截目标域名的请求并设置dont_filter=True:
class DomainDontFilterMiddleware: def process_request(self, request, spider): target_domain = 'piwi.wiesbaden.de' if target_domain in request.url: request.dont_filter = True return None
在settings.py中启用该中间件:
DOWNLOADER_MIDDLEWARES = { '你的项目名.middlewares.DomainDontFilterMiddleware': 543, }
各方法适用场景
- 方法1:适合多个爬虫需要统一处理同一域名的情况,全局生效无需修改爬虫代码。
- 方法2:仅对当前Rule提取的分页链接生效,精准度高,不影响其他请求。
- 方法3:实现最简单,所有目标域名的请求都会跳过去重,适合该域名下所有请求都不需要去重的场景。
内容的提问来源于stack exchange,提问作者Artsiom
相关产品推荐
相关产品推荐

