网络抓取给你提供的是原始记录,而原始记录很少是干净的。从三个目录中提取同一家公司、从四个零售商处提取同一个产品,或者从两个数据库中提取同一个人,你得到的行描述的是同一个真实世界的事物,但格式各不相同:"Acme Inc."在这里,"ACME, Incorporated"在那里,一个电话号码在一个数据源中用连字符分隔,在另一个中用空格分隔。在你决定哪些行指向同一个实体之前,你的数据集是一堆近似重复项,而不是可用的整体。
数据匹配是将这些分散、不一致的记录转化为单一协调视图的过程。本指南解释了为什么抓取的数据首先需要匹配,然后介绍核心概念:规范化、精确匹配与模糊匹配、模糊比较背后的相似度指标、通过分块使工作量可控、按阈值评分,以及产生每个真实实体一条干净记录的去重和实体解析步骤。读完本文后,你应该理解匹配管道是如何组合在一起的,以及如何在不被错误匹配淹没的情况下对其进行调优。
什么是数据匹配?
数据匹配是比较记录并决定哪些记录指向同一底层实体的任务,即使这些记录在字段上并不完全一致。它回答一个表面上简单的问题:这两行是同一件事吗?当跨多个数据源的回答是肯定的,你可以将它们合并成一条权威记录;当单一数据源中的记录被发现是相同的,你就删除重复项。
这之所以困难,是因为现实世界的数据是混乱的。网络抓取的数据尤其如此,因为它来自不同的人为不同受众构建的页面,没有共同的模式。同一个地址可能在一个列表网站上被缩写,而在公司自己的页面上被完整拼写。姓名带有错别字、重音符号、中间名首字母和顺序调换。日期、货币和计量单位各不相同。匹配的存在正是为了透过所有这些表面差异看到底层实体,而好的匹配是将你可以分析的数据集与悄然对所有内容重复计数的数据集区分开来的因素。
为什么抓取的记录需要匹配
几乎每个匹配任务都由几种模式驱动。第一种是多源收集:当你从多个网站抓取同类实体时,每个数据源以其自己的格式描述它,因此你需要匹配来对齐它们。第二种是源内重复:单个网站可能在两个 URL 下列出同一产品,或每周重新发布一则职位招聘,留下你必须折叠的重复项。第三种是数据增强:你有一条不完整的记录,想从另一个数据集中附加更多属性,这只有在你能够自信地链接两者的情况下才有效。在这三种情况中,底层问题都是相同的:许多嘈杂的记录,一个真实实体,以及需要做出的判断。
核心匹配概念
在了解管道之前,先固定词汇表很有帮助。匹配由一小组以不同方式组合的概念构成:你清洁数据使比较公平,你决定比较应该有多严格,你衡量当两个值不完全匹配时的相似程度,你设定什么构成匹配的规则。以下各节依次介绍每个概念。
规范化与标准化
匹配从清洁开始,因为比较原始抓取字段几乎总是不公平的。规范化(有时称为标准化)将每个值重写为一致的规范形式,使表面差异不再掩盖真实匹配。实践中,这意味着将文本转为小写、去除空白字符、去掉标点、展开或收缩缩写("St."到"Street")、将姓名和地址解析为组成部分,以及将日期、货币和单位转换为统一约定的格式。两条看起来不同的记录,"Acme Inc."和"ACME, Incorporated",在应用一致规则后可能会折叠为相同的规范字符串。
这一步骤的回报比其他任何步骤都多。跳过它会迫使你的匹配逻辑吸收每个格式怪癖,这既更慢又不够准确。首先投资于规范化是为下游使用准备抓取输出的更广泛纪律的一部分,在为 AI 和机器学习构建和清洗网络抓取数据中有深入介绍。输入越干净,之后的一切就越简单、越可靠。
精确匹配
精确匹配是最简单的技术:只有当选定的字段完全相同时,两条记录才匹配。当记录共享可靠的唯一标识符(产品 SKU、ISBN、已验证的电子邮件地址或政府 ID)时,它的效果非常好,因为这些键被设计为无歧义的。比较键,相等意味着同一实体。
限制在于精确匹配在面对变化时很脆弱。单个错别字、额外的空格、不同的大写,或缺少的中间名首字母,都会使描述同一事物的两条记录无法匹配。它在具有干净键的结构良好的数据上表现良好,在抓取数据中占主导地位的混乱自由文本字段上表现很差。这就是为什么大多数真实管道在存在可信键时使用精确匹配,而在其他所有情况下回退到模糊匹配。
模糊匹配
模糊匹配处理精确匹配处理不了的不完美数据。它不要求完全相同的值,而是测量两个值的相似程度,并产生一个相似度分数(通常以百分比表示),而不是是或否。该分数让你做出分级决策:将 95% 相似度视为有把握的匹配,60% 视为值得审查的可能情况,20% 视为不匹配。容忍度是关键,因为它允许错别字、缩写、重新排列的词语和部分值仍然解析为同一实体。
模糊匹配是抓取数据大部分价值所在,因为姓名、位置、产品标题和描述正是在数据源之间漂移的字段类型。权衡在于你现在有一个需要调整的旋钮。设置门槛太高,你会错过真正的匹配;设置太低,你会合并应该保持分开的记录。下一节中的指标是产生模糊匹配所依赖的相似度分数的工具。
相似度指标
相似度指标是一个公式,它将两个值转化为描述它们相似程度的数字。不同的指标适合不同类型的字段,好的匹配器会为每个字段选择正确的指标,而不是在所有地方使用单一度量。
- Levenshtein(编辑)距离计算将一个字符串转化为另一个字符串所需的最少单字符编辑(插入、删除、替换)次数。"Crawlbase"到"Crawbase"是一次删除,所以距离是 1。它非常适合捕捉短字段(如姓名和产品代码)中的错别字和小拼写变化。
- Jaccard 相似度将两个值作为集合进行比较,用它们交集的大小除以并集的大小。应用于字符串的单词或字符 n-gram,它不受顺序影响地测量重叠,这使它适合比较相同标记以不同顺序出现的多词字段。
- 余弦相似度将每个值表示为向量(词频、n-gram 或嵌入),并测量两个向量之间的角度。它不受长度影响地评分两段文本指向同一方向的程度,适合产品描述或地址等较长的文本。
如果需要一行说明,编辑距离的概念只是两个字符串之间小变化的计数:
# "Crawlbase" -> "Crawbase": delete one 'l' from rapidfuzz import distance d = distance.Levenshtein.distance("Crawlbase", "Crawbase") print(d) # 1
这些指标没有一个是普遍最佳的。技巧在于将指标与字段匹配:对容易出现错别字的短字符串使用编辑距离,对标记顺序调换的文本使用集合重叠,对较长的自由文本使用向量相似度。
分块与索引
将每条记录与其他每条记录进行比较是无法扩展的。两个各有 100,000 行的数据集意味着一百亿次比较,这是不可能完成的。分块(也称为索引)是使匹配可行的技术:不是比较所有对,而是将记录分组到共享某些便宜计算键的块中,只比较同一块内的记录。
分块键是真正匹配的记录很可能共享的粗略信号,例如邮政编码的前三个字符、公司名称的第一个词,或姓名的音标编码。在分块键上不一致的记录被认为是不匹配的,从不进行比较,这将比较次数减少了几个数量级。技巧在于选择足够宽松使真实匹配落在同一块中、但又足够严格使块保持小的键。许多管道在多次传递中使用几个分块键,这样被一个键遗漏的对仍有机会被另一个键捕获。
匹配过程如何运作
有了这些概念,匹配管道就是一系列逐步缩小问题的阶段。数据进入,被清洗,被分组以限制比较,被比较和评分,最终被解析为去重的实体。顺序很重要:每个阶段都假设前一个阶段已完成其工作。
第一步:准备并规范化数据
首先对每个数据源进行分析以了解其字段、格式和特点,然后应用上述规范化规则,使每条记录都以相同的方式表达。为每条记录分配或推导一个稳定的唯一标识符(无论是现有键、生成键,还是由多个字段构建的复合键)也很有帮助,这样你就可以在管道中跟踪记录并在以后引用匹配结果。跨数据源的一致模式和命名约定也是这一步骤的一部分;输入越统一,下游的一切行为就越好。
第二步:分块以生成候选对
运行分块策略,将完整数据集转化为更小的候选对集合(这些记录对可能是同一实体,因此值得详细比较)。这是使管道其余部分变得可负担的步骤,因此值得调优:检查你的分块键是否不会过于严格以至于明显的匹配被拆分到不同块中,并考虑多次传递以捕捉单个键会遗漏的对。
第三步:比较并为每对评分
对每个候选对,使用适合每个字段的相似度指标比较相关字段,然后将每字段的分数合并为该对的单个总体分数。合并可以是简单的加权平均(例如,比自由文本描述更重地加权已验证的电子邮件),也可以是学习的模型。这一步骤的输出是每个候选对的分数,表达你对两条记录是同一实体的置信度。
第四步:应用阈值决定匹配
分数本身不做任何决定,直到你设置阈值:高于它,该对是匹配;低于它,是不匹配。许多团队使用两个阈值加上中间带,自动接受高分,自动拒绝低分,将不确定的中间部分路由给人工审查。你设置这些临界值的位置是匹配中的核心调整决策,它直接在匹配出错的两种方式之间进行权衡,下文将介绍。
第五步:去重并解析实体
最后,根据决策行动。在单个数据源内,匹配的记录是要折叠为一条的重复项。跨数据源,匹配的记录被链接并合并为单个规范实体(这一步骤通常称为实体解析),将每个数据源的最佳属性合并为一条更丰富的记录。当超过两条记录以传递方式匹配时(A 匹配 B,B 匹配 C),它们被分组到代表该实体的一个聚类中。结果就是你一直想要的:每个真实世界事物一条干净的去重记录,可供分析。
当每个数据源以一致的形状到达时,匹配要容易得多,而这种一致性从提取开始。Crawlbase Crawling API 自动将支持的页面解析为干净的结构化字段,因此产品标题、价格和属性以可预测的模式返回,而不是你必须处理的原始 HTML。从统一的结构化输出开始意味着更少的规范化工作,以及在你的匹配管道运行之前更少的错误不匹配。
处理假阳性和假阴性
每个匹配系统都会犯两种错误,调整实际上是在平衡它们。假阳性是错误合并:两个不同的实体被评分为相同并被合并,用另一个实体的数据污染了一条记录。假阴性是遗漏的匹配:两条属于同一实体的记录被分开留置,在数据集中留下重复项。降低阈值会捕获更多真实匹配,但会引入更多假阳性;提高阈值可以避免错误合并,但会让更多真实匹配漏掉。没有能消除两者的设置,只有适合你用例的平衡。
偏向哪种错误取决于每种错误的代价。对于营销列表去重,偶尔的错误合并成本较低,遗漏重复项才是更大的烦恼,所以你可能会倾向宽松。对于合并财务或医疗记录,错误合并是严重的,所以你倾向保守,手动审查不确定的区间。实际工具是前文描述的两阈值审查区间、在评分中对可信字段加权,以及验证匹配样本(手动或使用模型)来测量真实错误率并调整。匹配是迭代的:你调整阈值和权重,测量,然后改进。
工具与方法
你不必从头构建所有这些。Python 的开源 Dedupe 库处理模糊匹配、去重和实体解析,从少量标记样本中学习匹配规则。对于在匹配前从自由文本中解析实体和关系,自然语言库(如 spaCy 和 NLTK)是常见选择。较重或受监管的工作负载有时需要将匹配、审查队列和治理打包在一起的商业主数据管理平台。
选择方法时,权衡几个因素:数据的量和复杂性、你需要的匹配准确性、预算、可用于运行和调优系统的内部专业知识、数据的敏感性,以及工具与现有技术栈的集成程度及其随增长的扩展性。匹配也很少单独存在;它是从提取到存储再到分析的更大流程中的一个阶段。关于周围的架构,参阅数据管道架构指南,由于匹配后的输出经常被模型消费,机器学习的网络抓取中的实践是一个有用的补充。你协调为哪种序列化格式也很重要;JSON 与 CSV 涵盖了合并记录的嵌套与扁平输出之间的权衡。
核心要点
- 匹配将多条记录协调为一个实体。 来自多个数据源的抓取数据以不同格式描述相同事物,匹配决定哪些行指向同一个真实世界实体。
- 规范化优先。 转为小写、修剪、展开缩写、标准化日期和单位,使比较公平,回报比任何其他步骤都多。
- 对键使用精确匹配,对其他一切使用模糊匹配。 在存在可靠唯一标识符的地方使用精确匹配,对混乱的自由文本字段使用带相似度指标(Levenshtein、Jaccard、余弦)的模糊匹配。
- 分块使匹配可扩展。 按便宜的共享键对记录分组,只在块内进行比较,将不可能的全对比较缩减为可行的规模。
- 阈值平衡两种错误。 匹配临界值的设置在假阳性(错误合并)和假阴性(遗漏匹配)之间进行权衡;根据你用例中每种错误的代价调整它。
常见问题
网络抓取中的数据匹配是什么?
数据匹配是比较抓取的记录并决定哪些记录指向同一真实世界实体的过程,即使它们在字段上并不一致。它让你能够跨数据源合并描述同一事物的记录,并删除单个数据源内的重复项,将一堆不一致的行转化为你实际可以分析的单一协调数据集。
精确匹配和模糊匹配有什么区别?
精确匹配要求比较的字段完全相同,当记录共享可靠的唯一键(如 SKU 或已验证的电子邮件)时效果很好,但在错别字和格式差异上会失败。模糊匹配测量两个值的相似程度,返回分级相似度分数而非是或否,因此它能容忍抓取的自由文本字段中常见的错别字、缩写和变体。
我应该使用哪种相似度指标?
这取决于字段。Levenshtein(编辑)距离适合容易出现错别字的短字符串,如姓名和产品代码。Jaccard 相似度将值作为标记集合进行比较,处理顺序调换的多词文本。余弦相似度通过将每个值视为向量来为描述或地址等较长文本评分。好的匹配器为每个字段选择指标,而不是在所有地方使用一个。
什么是分块,为什么它重要?
分块按便宜的共享键(如邮政编码前缀或名称的第一个词)对记录分组,只比较同一块内的记录。它之所以重要,是因为将每条记录与其他每条记录比较无法扩展:两组各 100,000 行意味着一百亿次比较。分块将其减少几个数量级,同时仍能捕获可能是真实匹配的对。
如何处理假阳性和假阴性?
两者都归结为你设置匹配阈值的位置。较低的阈值捕获更多真实匹配,但会造成更多假阳性(错误合并);较高的阈值避免错误合并,但会造成更多假阴性(遗漏匹配)。根据你用例中每种错误的代价选择平衡,使用将不确定对发送给人工审查的两阈值区间,更重地加权可信字段,并验证样本以测量和改进你的真实错误率。
我可以使用什么工具来匹配抓取的数据?
Python 的开源 Dedupe 库从少量标记样本中处理模糊匹配、去重和实体解析。spaCy 和 NLTK 等自然语言库在匹配前帮助从自由文本中提取实体。较大或受监管的工作负载可能需要商业主数据管理平台。从干净的结构化提取输出开始(如自动解析的字段)可以减少你的匹配工具需要完成的规范化工作。
大规模爬取任何站点,无需与基础设施对抗。
Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。
