使用 Python 的 hashlib 库对爬虫数据去重,核心是将 URL 或页面内容转换为固定长度的哈希值(如 MD5 或 SHA256),并存入集合或数据库进行比对。该方法适合单机中小规模去重,风险边界在于内存无法承载海量哈希表时需改用外部存储。
先说结论:hashlib 适合在内存中维护已抓取指纹,实现快速判重,但海量数据需配合数据库或布隆过滤器。
- 适合:单机爬虫、URL 去重、HTML 内容相似度初筛
- 先看:数据编码格式是否统一,避免哈希值不一致
- 建议:数据量超过百万级时,将哈希值存入 Redis 而非 Python 集合
快速处理思路
直接调用 hashlib 构造函数,传入编码后的字节串,获取十六进制摘要。
import hashlib
def get_hash(text):
return hashlib.md5(text.encode('utf-8')).hexdigest()
为什么会这样
哈希函数能将任意长度数据映射为固定长度字符串,比对哈希值比比对原始内容更快。
爬虫去重本质是判断“是否见过”,原始 URL 或内容长度不一,存储和比对开销大。hashlib 生成的摘要长度固定(如 MD5 为 32 字符),存入集合占用内存可控,字符串比对速度远快于内容比对。Python 官方文档指出 hashlib 提供了多种安全哈希算法和消息摘要算法的接口。
分步处理
第一步:导入库并选择算法。
import hashlib
# 推荐 SHA256,碰撞概率低于 MD5
algorithm = hashlib.sha256
第二步:统一数据编码。
必须将字符串转为字节串,否则报错。统一使用 utf-8 编码,避免不同系统默认编码导致哈希值不同。
data = "https://example.com/page".encode('utf-8')
第三步:计算哈希并判重。
维护一个全局集合存储已见过的哈希值。
seen_hashes = set()
hash_obj = algorithm(data)
hash_hex = hash_obj.hexdigest()
if hash_hex in seen_hashes:
print("重复数据,跳过")
else:
seen_hashes.add(hash_hex)
print("新数据,处理")
怎么验证是否生效
打印去重前后的数据计数,确认重复项被拦截。
在代码中加入日志,输出“总抓取数”与“实际处理数”。若两者差值大于 0 且符合预期重复逻辑,说明生效。检查日志中是否出现“重复数据,跳过”字样。
常见坑
编码不一致导致漏判。不同页面可能内容相同但编码声明不同,必须先统一解码为 unicode 再编码为 utf-8 后哈希。
内存溢出风险。Python 的 set 存储在内存中,若哈希值数量达到千万级,单机内存可能不足。此时应改用 Redis 集合或布隆过滤器。
哈希碰撞理论风险。MD5 存在碰撞可能,虽概率极低,但对安全性要求高的场景建议改用 SHA256。
常见问题
MD5 和 SHA256 选哪个?
优先选 SHA256,安全性更高且碰撞概率更低。
MD5 计算速度略快但已不再推荐用于防碰撞场景。SHA256 是当前通用标准,性能差异在爬虫去重场景中通常可忽略。
数据量太大内存放不下怎么办?
将哈希值存入外部数据库如 Redis,或使用布隆过滤器。
Python 集合受限于单机内存。Redis 的 set 结构支持持久化和分布式共享。布隆过滤器能以极小空间判断元素是否存在,允许少量误判。
只对 URL 去重还是对内容去重?
建议同时做,先 URL 去重,再内容去重。
URL 去重成本低,能过滤明显重复请求。内容去重能发现不同 URL 指向相同内容的情况(如参数顺序不同)。先检查 URL 哈希,抓取后再检查内容哈希。
参考来源
- Python 官方文档,hashlib — 安全哈希与消息摘要,https://docs.python.org/3/library/hashlib.html