You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy:如何使用LinkExtractor跳过已抓取的链接

问题解答

你的需求完全可行,下面给你几种高效的实现方式:

一、优先用Scrapy内置去重(最省心)

Scrapy自带请求去重功能,默认通过RFPDupeFilter自动过滤已经请求过的URL,根本不用自己写哈希存储和校验逻辑。只要确保:

  • 项目settings.py里DUPEFILTER_CLASS用默认的scrapy.dupefilters.RFPDupeFilter(默认就是这个,不用改)
  • 请求的dont_filter参数别设为True(默认是False,会自动走过滤)

要是只是不想重复抓取,这个方案是最优解,省得自己维护链接列表。

二、自定义LinkExtractor过滤已抓取链接(适合需要保留自定义链接列表的场景)

如果必须基于你自己维护的links.txt来过滤,用LinkExtractor的process_value参数就能实现,提取链接时直接跳过已抓取的:

1. 初始化时缓存已抓取哈希到内存

把links.txt里的哈希在爬虫启动时读一次存到内存,避免每次处理请求都读文件(你代码里TODO的部分):

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.crawled_hashes = set(self.read_hash_list(self.filename))  # 用set存,查询比列表快多了

2. 写链接过滤函数

定义一个函数,检查提取到的URL的哈希是否在已抓取列表里,不在就返回原URL,否则返回None(返回None会被LinkExtractor跳过):

def filter_crawled_links(self, url):
    url_hash = hashlib.md5(url.encode('utf-8')).hexdigest()
    return url if url_hash not in self.crawled_hashes else None

3. 修改Rule里的LinkExtractor

把process_value参数指向上面的过滤函数:

rules = [
    Rule(
        LinkExtractor(
            deny_domains='www.youtube.com',
            process_value=self.filter_crawled_links
        ),
        callback='parse_item',
        follow=True
    )
]

4. 更新内存缓存

在check_dupes里,新增哈希后要同步更新内存里的crawled_hashes,避免后续判断出错:

def check_dupes(self, response):
    new = False
    new_hash = hashlib.md5(response.url.encode('utf-8')).hexdigest()
    if new_hash not in self.crawled_hashes:
        self.write_hash_list(response.url, self.filename)
        self.crawled_hashes.add(new_hash)  # 同步内存缓存
        new = True
    return new

三、优化你原有代码的核心问题

你原来的代码每次check_dupes都读一次文件,性能拉胯,改成初始化时读一次内存缓存,并用set存储哈希(查询速度远快于列表),能大幅提升爬虫效率。

如果不需要自定义存储已抓取链接,强烈建议用第一种内置去重的方式,代码更简洁,性能也更稳定。

内容的提问来源于stack exchange,提问作者old_hands

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:05:34