排名追踪 API:用两个数据源自建 Google 排名追踪器

重点摘要

一个免费,只能看到自己的网站;另一个收费,什么都能看到。把两者合起来,你就拥有一个比席位授权更便宜的排名追踪器。以下是搭建方法、请求量计算和护栏。

「排名追踪 API」不是一个东西。开发者搜索 “rank tracking API” 时,通常想要一个返回排名的单一端点,而市场用供应商的清单文章来回应。诚实的答案是:你需要两个数据源,它们回答不同的问题。

Search Console API 免费、官方,并且永久限定于你能验证的资源。SERP API 付费、非官方,可以查询任何地方的任何关键词,包括你从未排上过的关键词。两者单独都不是排名追踪器。合在一起,大约就是 120 行 Python 加一条 cron。

这就是那套搭建方案。它假设你能跑脚本、能存文件,不假设你想做一款产品。

完成后你会得到什么

适合谁: 已经拥有 Search Console 权限,想按计划拿到排名、又不想按席位付费的开发者或技术营销人员。

完成时你手上会有什么: 两个能用的拉取函数,每次运行一个合并输出文件,以及一条让数字无法对你说谎的比较规则。

时间: 首次搭建约 90 分钟,之后每次运行约 10 分钟复核。

完成的样子: 一个带日期的 JSON 文件,包含按查询和按设备划分的自有排名、一份冻结关键词列表的实时 SERP 快照,以及与上一次运行的简短差异。

开始之前:每个数据源能做什么、不能做什么

把这个分工做对,剩下的搭建就是机械劳动。做错了,你会花一个月造出要么没用、要么很贵的东西。

Search Console API

SERP API

谁的排名

仅你已验证的资源

任何人,包括竞争对手

关键词

你已经出现过的查询

你输入的任何关键词

成本

免费

按请求计费

设备拆分

有,作为维度

有,按请求

地区

你有排名的国家

供应商支持的任何地区

数据类型

点击、展示、平均排名的汇总

某一时刻的结果页

历史深度

你请求的区间

仅从你开始存储那天起

官方性

Google 自己的数据

第三方对公开页面的读取

两个数据源会互相矛盾,而这种矛盾是信息而不是缺陷。Search Console 对区间内每一次展示、每一台设备取平均。SERP 拉取是某一刻的一个结果页。直接把两者相比,你会去追根本不存在的下跌。所以第 5 步定义了一条比较规则。

写代码前值得知道的三个数字。 Search Console API 每次请求接受 1 到 25,000 的行数上限,默认 1,000,所以一个中型站点可以在一次调用里拉取三个月的查询和设备数据。它允许每站点、每用户每分钟 1,200 次查询。它还按 10 分钟一段来计量负载配额,长区间比短区间更贵——这正是 Google 自己的指南说要避免重复查询同一批数据的原因。

双数据源架构图:Search Console API 提供自有站点排名,SERP API 提供外部关键词快照,汇入同一个合并追踪文件

两个数据源,一个输出。Search Console 回答「我出现在哪里」,SERP API 回答「页面长什么样」。

第 1 步:写任何代码之前先冻结关键词集合

一个每次运行都拉取不同关键词列表的追踪器,无法回答是否有任何变化。先把列表定下来,然后保持一个季度。

分三组,来源各不相同。

  • 来自 Search Console: 过去 90 天展示量至少 20 的每一个查询。这些不是你选的,是你的展示量选的。这一组的变动才有意义,因为背后已经挂着真实需求。
  • 来自业务: 对应收入的 10 到 20 个查询,无论你现在有没有排名。
  • 来自竞争对手: 竞争对手排上而你没排上的查询。这些需要 SERP API,因为 Search Console 永远不会展示它们。

把列表写进文件,纳入版本管理,把新增当作一次有意的变更,而不是慢慢漂移。

第 2 步:免费拉取你自己的排名

这一半是官方的、免费的,并且给你任何 SERP API 都没有的设备拆分和点击数据。

python
from google.oauth2 import service_account
from googleapiclient.discovery import build

service = build(
    "searchconsole", "v1",
    credentials=service_account.Credentials.from_service_account_file(
        "gsc-key.json",
        scopes=["https://www.googleapis.com/auth/webmasters.readonly"],
    ),
)

body = {
    "startDate": "2026-06-14",
    "endDate": "2026-09-11",
    "dimensions": ["query", "device"],
    "type": "web",
    "dataState": "final",
    "rowLimit": 25000,
}

rows = service.searchanalytics().query(
    siteUrl="sc-domain:example.com", body=body
).execute().get("rows", [])

这个请求里有两个细节承担了大部分工作。

dataState: "final" 排除 Google 可能还会修订的新鲜数据。没有它,最近两三天的数据会在每次运行之间变动,你的差异里就会出现从未发生过的波动。

dimensions: ["query", "device"] 是让输出在日后有用的那一项。现在加上设备不花任何代价。日后再去重拉三个月历史,要花一整次运行,而且对你已经跳过的那些天什么也补不回来。

预期输出: 每个查询与设备的组合一行,含点击、展示、CTR 和平均排名。

质量检查: 行数应低于 25,000。如果正好是 25,000,说明被截断了,需要用 startRow: 25000 再调一次。

如果失败: 403 通常意味着服务账号邮箱从未被添加为该资源的用户。在 Search Console 里加上,等几分钟,重试。

第 3 步:拉取你在自有数据里看不到的 SERP

后半部分覆盖 Search Console 在结构上做不到的一切。这是一个最小可用的调用。

python
import base64, json, urllib.request

LOGIN, PASSWORD = "your-login", "your-password"

def serp(keyword, depth=100):
    token = base64.b64encode(f"{LOGIN}:{PASSWORD}".encode()).decode()
    payload = json.dumps([{
        "keyword": keyword,
        "location_name": "United States",
        "language_name": "English",
        "depth": depth,
    }]).encode()
    request = urllib.request.Request(
        "https://api.dataforseo.com/v3/serp/google/organic/live/advanced",
        data=payload,
        headers={"Authorization": f"Basic {token}",
                 "Content-Type": "application/json"},
        method="POST",
    )
    return json.loads(urllib.request.urlopen(request, timeout=120).read())

把 `depth` 设为 100,不要设 200。 我们在 2026 年 9 月用六个查询请求 200 条来测过这件事。Google 返回了 83 到 128 条自然结果就停止了,整个测试中最深的排名是 142。完整测试在这里。请求 200 并不会拿到 200 条,而且视供应商而定,它可能仍按你请求的深度计费。请求 100,你几乎总能收到存在的全部结果。

柱状图:六个测试查询中 Google 返回的自然结果数量,全部低于 130,与请求的深度 200 形成对照

请求 200 条,实际收到 83 到 128 条。在多数商业查询上,超过约 140 的深度买不到任何东西。

预期输出: 一个 JSON 载荷,其中自然结果条目含排名、URL、标题和域名。

质量检查: 确认载荷在存在 AI Overview 时含有 ai_overview 条目类型。如果你只提取 organic 条目,就会漏掉一个页面保住排名却丢掉点击的原因。

如果失败: 401 是 base64 或凭据错误。40200 一类代码表示账户余额为空,这是第一个月最常见的失败。

第 4 步:存原始载荷,而不是摘要

这是人们跳过之后会后悔的决定。

存一张排名表格,直到你需要问一个没预料到的问题时就不够用了:SERP 是不是变长了、视频是不是占了上风、竞争对手是不是进场了、AI Overview 是不是出现在首屏上方。摘要回答不了这些。原始载荷可以,而且零额外成本。

务实版本是:每次运行写一个文件,以日期和时间命名,装上合并后的输出。保留最近 90 天。小到可以放进代码仓库,完整到能重新回答旧问题。

第 5 步:排期之前先写下比较规则

一个把上次运行和这次运行相比的追踪器,大多数日子都会发出误报。我们自己的数字说明了原因:在 124 个展示量至少 30 的查询中,平均每个查询隔一天移动 4.57 个名次。掉四个名次,不过是又一个星期二。

所以规则需要一个阈值和一个方向。

text
仅在以下条件全部满足时报告某个查询:
  - 与上次运行相比的名次变化绝对值达到 5 或以上,并且
  - 该查询在比较窗口内展示量至少 20,并且
  - 该变化无法由设备构成的变化解释

按查询类别分组输出:money、comparison、brand、informational。
不要提出修复建议。

设备那一条不是装饰。同一个查询在移动端和桌面端可以相差 11 个名次,如果两次运行之间设备构成发生变化,混合后的数字也会变。我们另外测过这件事,幅度大到足以伪造出一种趋势。

成本

供应商价格会变,所以建模,别追报价。

  • 一个关键词每天查一次、查 30 天,是每月 30 次请求。
  • 200 个关键词的集合每天查,是每月 6,000 次请求。
  • 同一个集合每周查,是每月约 860 次请求。
  • Search Console 那一半是免费的,无论里面装多少个关键词,每次视图都是一次请求。

这个乘法就是整个决策。「我该不该买个工具」几乎总能坍缩成它:算出每月请求数,乘以你的单次请求价格,再和席位授权比一比。大关键词集合每天追踪,通常订阅更便宜。小集合每周追踪,通常 API 更便宜。追踪一份冻结的列表,API 这一侧就会一直很小。

什么时候该买而不是自己搭

如果你想把排名放进自己的管道、已经持有 SERP API 凭据,或者出于排名之外的 reasons 需要原始结果页,那就自己搭。

如果你需要今天之前的历史排名、需要同一批关键词的十个地区和五种设备,或者团队里没人愿意维护一个 cron 任务,那就买。供应商的清单文章正是因为这个原因值得一读,而拥有一套「搭它的人换团队后就停摆」的基础设施,是有真实成本的。

如果你真正需要的输出是一份写好的周报而不是 JSON 文件,Codex 报表工作流从同样的两个数据源出发,最终落到一份文档。要在文件之上做告警,监控设计指南讲了阈值。

Auspia 观点:排名追踪 API 这个问题,本质上是数据所有权问题。Search Console 免费给你自有资源的官方数据,而且永远会给。其余一切都是你付费买来的快照。先把免费的一半搭起来,付费的一半只加在它确实回答了你真实问题的地方。

常见问题

Google 提供排名追踪 API 吗? 没有公开的。Search Console API 返回你已经出现过的查询的平均排名,接近但不是同一回事。它查不了你没有排名的关键词,也查不了竞争对手。

SERP API 能挖多深? 供应商会接受远高于 200 的深度值,但 Google 在多数商业查询上大约到 100 至 140 之间就不再提供结果。要求更多并不会产生更多结果。

我该用每日还是每周检查? 普通关键词集合用每周。每日只用于一小串收入关键词。对大集合做每日检查会把成本乘以七,而且大多是在测量噪声,因为我们自己数据里的日均移动是 4.57 个名次。

为什么我的 API 数字和我的排名工具不一样? 设备不同、地区不同、时刻不同,数据源往往也不同。那个数字是个样本。在得出任何变化结论之前,先把请求里的地区和设备固定下来重拉一次。

智能体能替我做这件事吗? 能,而且很合适,因为这项任务每次运行的形状都一样。关于智能体在排名工作中能承担的范围,见 SEO 智能体实战指南。把比较规则写进一份指令文件,让智能体产出差异,而买还是搭的决定留给人。

作者:Rowan Blake,Auspia 内容自动化分析师,负责 100 多条发布管道。Rowan 撰写关于自动化数据管道、定时报表,以及在你不在时仍自行运转的系统的维护成本。

探索此主题

继续阅读同一增长脉络