Scrapy数据去重与增量更新完全指南
📂 所属阶段:第二阶段 — 数据流转(数据处理篇)
🔗 相关章节:Pipeline管道实战 · 数据清洗与校验
目录
快速入门场景
做爬虫时最常遇到的两个痛点:
- 重复爬取同一页面或内容,浪费带宽、时间和服务器资源;
- 全量重爬,无法第一时间捕获新增或变更的数据。
本文会覆盖从简单单机去重到带智能调度的增量爬取的完整方案,所有代码均可直接复用,帮你快速落地高性价比的爬虫策略。
Redis指纹去重实现
基础可复用Pipeline
这是最通用的Redis指纹去重方案,支持自定义指纹字段和过期时间。
核心思路:
- 将Item中你关心的字段(如
url、title)组合成一个固定顺序的字符串; - 计算SHA256哈希值作为“数据指纹”;
- 用Redis的
SETEX命令将指纹保存一段时间,下次遇到相同指纹直接丢弃。
配置文件示例
在 settings.py 中添加如下配置:
URL标准化与请求级去重
同一个页面可能以多种不同的URL形式出现:
- 有的带
www,有的不带; - 末尾有无斜杠;
- 带各类追踪参数(
utm_source、gclid等)。
如果直接进行去重,这些URL会被认为是不同的页面,导致重复爬取。因此,在指纹计算前先做URL标准化,能大幅提升去重效果。
URL标准化Pipeline
优先级调整:在 settings.py 中确保标准化Pipeline在去重Pipeline之前执行,例如:
本地/Redis布隆过滤器优化
布隆过滤器是一种高效的概率型数据结构,用极少的内存快速判断一个元素是否可能存在于集合中。
- 优点:千万级数据去重时内存开销极小,查询速度极快;
- 缺点:存在极低的误判率——把一个不存在的元素误判为存在(但反过来不会,已存在的元素绝不会被漏判)。
你可以根据数据规模选择本地内存版布隆过滤器,或者使用Redis提供的布隆过滤器模块。
本地布隆过滤器(适合单机千万级以下)
依赖 mmh3 和 bitarray 库:
⚠️ 注意:本地布隆过滤器在进程重启后会丢失所有记录,只适合短期大量去重或对重启不敏感的临时场景。如需持久化,可以考虑将布隆过滤器数据定期保存到磁盘或改用Redis版布隆过滤器。
时间戳+智能增量抓取
增量抓取的核心思路:只抓取上次爬取之后新增或更新的数据,从而避免重复抓取历史内容。
时间戳增量Spider
下面是一个基于Redis记录“上次抓取时间戳”的增量爬虫示例,适合文章、新闻等发布时间明确的数据源。
要点解析:
- 时间基准:用Redis存储上一次爬取的完成时间,每次爬完更新;
- 过滤逻辑:仅处理发布时间晚于该基准的数据;
- 兜底策略:首次运行时设置一个较旧的初始时间(如30天前),避免遗漏近期刚更新的数据。
核心性能优化
内存LRU缓存 + Redis批量管道
这是最立竿见影的性能优化方案:
- 内存LRU缓存:快速过滤最近爬过的热门数据,减少对Redis的频繁访问;
- Redis批量管道:将多条指纹写入命令批量发送,减少网络往返次数。
2个高频问题解决
问题1:长时间运行内存溢出
原因:LRU缓存无限增长或Redis指纹过期时间过长,导致内存不断膨胀。
解决方法:
- 调整LRU缓存大小,比如根据服务器内存情况设置
lru_max = 5000; - 缩短Redis指纹过期时间
DUPLICATE_EXPIRE_DAYS = 3; - 定期(如每周)人工清理Redis去重库,或者使用Redis的
FLUSHDB命令。
问题2:Redis连接超时/断开
原因:网络抖动或Redis服务负载过高。
解决方法:在创建Redis连接时增加超时、重试和健康检查配置。
指数退避重试的意思是:第一次重试等待1秒,第二次等待2秒,第三次等待4秒(最多等待10秒),能有效避免瞬时连接失败导致整个爬虫中断。
💡 核心总结:
- 简单场景:URL标准化 + SHA256 Redis指纹去重,就能解决大多数重复问题;
- 大规模场景:本地布隆过滤器 + Redis批量管道,实现低成本高性能去重;
- 增量爬取:优先使用基于时间戳的增量方案,有条件再加入动态调度;
- 容错与监控:务必配置Redis重试和健康检查,防止单点故障导致爬虫瘫痪。

