处理爬虫数据时,数据去重与清洗往往是最让人头疼的环节。看似简单的操作背后,其实隐藏着不少细节问题。例如,set() 去重会丢失原始顺序,清洗时需要先对字符串进行标准化并处理 HTML 实体,而字段级去重通常比全文哈希更可靠——通过关键字段组合生成指纹,才能保证去重质量。

为什么直接使用 set() 去重会丢失顺序?
很多开发者习惯用 list(set(data)) 快速去重,虽然省事,但 Python 的 set 天生无序。原始抓取顺序——比如按时间、热度或分页排列——会彻底被打乱。如果后续业务逻辑要求“第一条是最新数据”,这就等于埋下一个隐患。
更稳妥的做法是改用 dict.fromkeys(),它能在 Python 3.7+ 中保持插入顺序:
cleaned = list(dict.fromkeys(raw_list))
注意,这个方法只适用于元素可哈希的情况(如 str、int、tuple)。如果数据中包含 dict 或 list 这类嵌套结构,会直接报 TypeError。此时需要先将数据转为 JSON 字符串再去重,但要注意浮点精度、键顺序等细节,否则容易出错。
清洗 HTML 标签和空白字符,这些坑你踩过吗?
很多人用 re.sub(r']+>', '', text) 简单粗暴地删除标签,结果遇到 里的 JavaScript、 里的 CSS,或者未闭合标签(比如
)时,正则直接失效,甚至误删了正文内容。
推荐使用 BeautifulSoup 配合 get_text(),但有几个细节值得留意:
strip=True参数必须显式传递,否则首尾空格会残留- 多个连续换行或空格会被压缩成单个空格。如果希望保留段落结构,可以改用
get_text(separator=' ', strip=False),再手动用re.sub(r'\s+', ' ', ...)处理 - 遇到
、—等 HTML 实体,一定要用html.unescape()解码,否则清洗后还会留着&符号,看起来很不干净
去重之前,先做标准化,否则 '北京' 和 ' 北京 ' 会被当成两条数据
爬虫数据里常见的问题包括:多余空格、全角/半角符号混用、大小写不一致、URL 中 http 和 https 混存等。如果直接拿原始字符串去比对,等于白费功夫。
建议统一走标准化管道:
def normalize(s): if not isinstance(s, str): return s s = html.unescape(s.strip()) s = re.sub(r'[^\w\su4e00-u9fff]', '', s) # 保留中文、字母、数字、空格 s = re.sub(r'\s+', ' ', s) return s.lower()
之后再用 dict.fromkeys([normalize(x) for x in raw_list]) 去重。不过,标准化后如果需要回溯原始值,最好用元组 (normalized, original) 来存储,避免丢失原始数据。
面对重复 ID 但内容微调的数据,该用字段级去重还是全文哈希?
电商商品页抓取时,经常遇到 ID 相同但价格或库存变动的情况。如果按 ID 去重,会丢失重要变更;而按全文哈希去重,又可能因为广告位、时间戳等噪声字段,导致相同内容被判定为不同。
务实的做法是提取业务关键字段,做组合哈希:
- 只取
title、price、sku_id(不含update_time、view_count) - 拼接后用
hashlib.md5(...encode()).hexdigest()[:8]生成简短指纹 - 用
collections.defaultdict(list)按指纹分组,再通过人工或规则判断是否真的重复(比如价格差超过 10% 就保留两条)
别依赖单一维度。真实数据永远在边界上——ID 可能填错,文本可能有错别字,哈希碰撞虽然概率低,但并非零。留痕比自动裁决更重要。
