SERP 结果里的三个 URL:link、url、source_url 到底该用哪个
采集搜索结果时,很多人直接拿 link 存库。三个月后会发现三个问题:同一个页面出现多行、统计里混进了 google.com、域名分布对不上。根因不是采集,是没分清响应里几个 URL 字段的语义。
这篇把字段拆开,给一套可落地的规范化方案。
字段语义
SerpBase 的网页搜索结果里,与 URL 相关的字段有四个(均为可选,按解析情况返回):
| 字段 | 含义 | 用途 |
|---|---|---|
link |
解析器返回的主链接 | 通常直接可用 |
url |
规范化后的目标 URL | 一般与 link 相同 |
source_url |
仅当观察到 Google 跳转/来源 URL 时返回 | 溯源、调试,不是目标地址 |
display_url / display_link |
展示用域名或文本 | 展示,不可用于去重 |
另外,自然结果里可能有 sitelinks 数组,每条也带 link、url、source_url——站内链接不能混进主结果统计,否则一个页面会被算成五条。
为什么不能直接存 link
三个现实问题:
一、跳转链。 Google 有时返回 google.com/url?sa=t&url=... 形态的链接。这类地址放在 source_url 里,若拿它当目标地址,统计会全部算到 google.com 头上。
二、同一页面的多种写法。 http 与 https、带不带 www、尾斜杠有无、utm_* 跟踪参数——不同关键词下可能各出现一次,直接存就是重复行。
三、别名与规范化差异。 link 和 url 大多数时候相同,但不保证永远相同;去重应该基于规范化结果,而不是原始字符串。
规范化函数
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
TRACKING = {
"utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content",
"gclid", "fbclid", "ref", "source",
}
def canonical_url(raw: str) -> str:
parts = urlsplit(raw.strip())
host = parts.netloc.lower()
if host.startswith("www."):
host = host[4:]
query = [(k, v) for k, v in parse_qsl(parts.query, keep_blank_values=True)
if k.lower() not in TRACKING]
path = parts.path.rstrip("/") or "/"
return urlunsplit(("https", host, path, urlencode(query), ""))
规则按需调整,但方向固定:统一 scheme、去 www、去尾斜杠、去跟踪参数、丢 fragment。查询参数不要一刀切删——有些页面靠 ?id= 区分内容,删了就合并错了。
存储与去重
row = {
"keyword": kw,
"rank": item.get("rank"),
"canonical": canonical_url(item.get("url") or item["link"]),
"raw_link": item["link"],
"source_url": item.get("source_url"), # 保留,做溯源
"display_url": item.get("display_url"),
"is_sitelink": False,
}
三个原则:
- 唯一键用
canonical+keyword,不用原始link - 原始字段全部保留,规范化只是新增一列,不覆盖原文
source_url单独存,它证明「这条结果来自哪次 Google 跳转」,是排障和审计的凭据
统计时的口径
- 独立域名数:按
canonical的 host 去重,不要用display_url(它可能带省略号) - 首次出现:按
canonical去重后取最小 rank - 新老页面对比:同一个
canonical跨时间比较,而不是比较两次的原始 link
五个坑
坑 1:用 source_url 当目标地址。 统计全跑到 google.com,域名分析直接失真。
坑 2:用 display_url 做去重。 它是展示文本,可能被截断,也不是唯一标识。
坑 3:把 sitelinks 混进主结果。 一个页面变成多条,排名分布全错。
坑 4:无脑删所有查询参数。 有些页面靠参数区分内容,删了就误合并。
坑 5:不保留原始字段。 规范化规则一旦调整,没有原文就无法回溯,只能重新采集(又花 credits)。
小结
URL 处理的链路:认字段(link/url/source_url/display_url)→ 规范化(scheme/host/path/query)→ 用 canonical 去重 → 原始字段留档。这套东西不复杂,但它是搜索数据质量的地基——地基歪了,后面的排名、域名、竞品分析全是错的。
字段的可空性与语义以 SerpBase 文档 为准,source_url 只在观察到跳转时返回。你们的 SERP 数据是怎么去重的?评论区聊聊。

浙公网安备 33010602011771号