Scrapy CrawlSpider爬取网站链接出现大量重复数据问题排查
问题排查
你的代码出现大量重复结果,是4个核心逻辑错误导致的:
- 去重列表
url_list定义在parse方法内部,每次发起新请求调用parse时都会重置为空列表,只能过滤单个页面内的重复链接,完全无法实现跨页面去重。 - 遍历选择器写的是
response.css('div'),页面存在大量嵌套的div标签,很多内层div和外层div包含完全相同的a链接,哪怕单页内也会反复匹配到同一个链接;同时你提取文本时取的是整个response的全量文本,和当前遍历的div块无关,导致同一条数据重复生成。 - CrawlSpider类自带核心调度方法就叫
parse,你自定义的同名回调会覆盖框架原生逻辑,导致内置的请求去重、规则跟进机制失效,重复发起相同URL的请求。 - LinkExtractor规则
allow='/'会匹配所有带斜杠的链接,没有做范围限制,会重复抓取相同入口的链接。
修复后可直接运行的代码
from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class SuperSpider(CrawlSpider): name = 'spider' allowed_domains = ['quotes.toscrape.com'] start_urls = ['http://quotes.toscrape.com/'] base_url = 'http://quotes.toscrape.com' # 回调禁止命名为parse,会覆盖CrawlSpider内置逻辑 rules = [ Rule(LinkExtractor(allow=r'/page/'), callback='parse_item', follow=True), Rule(LinkExtractor(allow=[r'/author/', r'/tag/']), callback='parse_item', follow=False) ] # 类级别全局集合,存储所有已经处理过的URL,实现跨请求去重 crawled_urls = set() def parse_item(self, response): # 当前页面已经处理过直接跳过 if response.url in self.crawled_urls: return self.crawled_urls.add(response.url) # 提取页面有效文本,过滤空内容和多余空白 page_text = ' '.join([t.strip() for t in response.css('::text').extract() if t.strip()]) # 一次性提取当前页所有链接,转集合自动去重 all_links = set(response.css('a::attr(href)').extract()) for link in all_links: # 跳过空链接、页内锚点 if not link or link.startswith('#'): continue yield { 'current_page': response.url, 'link_without_base_url': link, 'page_content': page_text }
修复说明
- 全局去重逻辑移到类属性层级,所有爬取请求共享已爬URL记录,从根源避免跨页面重复处理。
- 修正回调方法命名,保证CrawlSpider原生的请求去重、链接跟进逻辑正常运行。
- 放弃遍历所有div的低效写法,直接提取页面全量链接后用集合自动去重,避免嵌套标签导致的单页内重复匹配。
- 调整LinkExtractor规则,区分可跟进的分页列表和不需要跟进的详情页,减少无效重复请求。
- 文本提取时过滤无意义的换行、空白字符,输出内容更干净。
内容的提问来源于stack exchange,提问作者mmalagocki
相关产品推荐
相关产品推荐

