Python 排名追踪:用 SQLite 记 Google 排名,不用 $99/月
排名追踪订阅从 $99/月起上不封顶,但产品的机械内核很小:拉一次 SERP、找到你的域名、存下位置、跟上一次做差。这篇走一遍 rank_tracker——zens-ink 包里 SQLite 存储的排名追踪 CLI,六条命令纯标准库,每个词每次检查只花一次 Serper 调用。zens.ink 两个月的真实快照带出三个比仪表盘更有用的发现:品牌词从 #1 滑到 #2 是被自家商店页顶掉的、同一分钟内 SERP 方差让一次快照「不在前 20」下一秒又回到 #2、以及 GSC 均值排名和实时匿名 SERP 完全对不上的解释。附每周检查的成本账和时点排名测量的诚实边界。
一句话——排名追踪只需要四件事:拉 SERP、找域名、存快照、跟上次做差。python -m zens_ink.rank_tracker 用纯标准库做完了,SQLite 存在 ~/.zens_ink/ranks.db,每词每次检查一次 Serper.dev 调用。zens.ink 两个月的真实快照跑出三个发现:品牌词掉到 #2 是自家商店页抢的位;同一个词连续检查「不在前 20」和「#2」一分钟内交替出现;GSC 说均值第 7 的词实时匿名 SERP 根本找不到。pip install zens-ink,配好 SERPER_API_KEY,完事。
排名追踪的定价页自成一类:看一列关键词,$99/月起步。但这台产品的机械内核只有四步——拉一次 SERP、在里面找到你的域名、存下位置、跟上一次快照做差。这是周末级的 Python 工作量,zens-ink 包里就有现成的 rank_tracker:SQLite 存储、每词每次检查一次 Serper.dev 调用、纯标准库。
这篇用它跑了真实数据——包括 zens.ink 两个月的快照,跑出三件任何仪表盘都不会主动告诉你的事:品牌词被自家商店页顶掉、同分钟的 SERP 方差事故、以及一个改变你读 GSC 数字方式的实时 vs 均值落差。
工具
用过其他 zens-ink CLI 的话,形状很熟。装一次,.env 里放个 Serper key(免费档每月 2500 次调用),追踪器对着本地 SQLite 文件 ~/.zens_ink/ranks.db 离线优先地跑:
pip install zens-ink
# .env: SERPER_API_KEY=... (免费: serper.dev)
六个动作,没有配置文件:
python3 -m zens_ink.rank_tracker add "open source seo tools,seo cli tool" --domain zens.ink
python3 -m zens_ink.rank_tracker check # 拉 SERP,写快照
python3 -m zens_ink.rank_tracker status # 每词最新位置
python3 -m zens_ink.rank_tracker trend # 最新 vs 上一快照
python3 -m zens_ink.rank_tracker history "zensink"
python3 -m zens_ink.rank_tracker remove "old keyword"
add 和 remove 之外全是只读,直到你再次 check——这正是每日快照安全的原因:check 是唯一花 API 调用、写位置的动作。
一次真实检查
17 个词的新鲜 check(zens.ink 的词和另一个站的混在一起、分开打标签——域名是词级绑定的,一个库能追多个站):
$ python3 -m zens_ink.rank_tracker check
checked 17/17 keywords:
# — blind signing
# — bluf seo
# — content brief template
# — geo score methodology
...
# — wallet drainer
# 2 zensink
— 是追踪器说「域名不在拉回的 SERP 里」——默认深度 20 条结果,就是匿名美区桌面 SERP 的前 20 没有你。只有品牌词 zensink 带回了位置:第 2。
这是一个年轻站点 Google 可见性的诚实状态,值得停一下:同一站点的 GSC quick-win 挖掘找到过均值 7-21 位的词,而实时匿名 SERP 里根本找不到它们。这个落差下面细说——本次练习挖出的最有用的东西。
发现一:品牌词滑了,赢家是我们自己
history 打印一个词的全部历史快照。品牌词两个月的数据:
$ python3 -m zens_ink.rank_tracker history "zensink"
history: zensink
2026-10-13T00:11:19Z # 2 https://zens.ink/
2026-10-13T00:08:15Z # —
2026-10-13T00:07:06Z # 2 https://zens.ink/
2026-08-14T18:03:26Z # 1 https://zens.ink/
2026-08-14T17:47:57Z # 1 https://zens.ink/
八月份是 #1,十月是 #2。顶掉我们的是什么?把 SERP 拉回来人工看一眼:排在前面的是产品的 Creem 商店页——同一个产品的第二张门面。品牌词 SERP 里自家页面占两席,严格说是好事(更大的点击面),但也意味着 SEO 意义上的「品牌词第一」不再是单选题。
对排名追踪的启示:位置变化先查谁抢了位,再决定要不要反应。掉一位可能是在输,也可能是在扩大地盘。没有 SERP 内容的纯数字仪表盘分不出这两种。
发现二:一分钟内,「不在前 20」和「#2」同时为真
看上面的时间戳:00:07:06 是 #2,00:08:15 是 —(不在前 20),00:11:19 又是 #2。三分钟、三次检查、两个互相矛盾的答案。
这不是 bug,是 SERP 数据的现实:API 返回的搜索结果会在快照之间轮换(不同机房、不同索引分片),Google 自己也按上下文变结果。商业追踪器把这个方差藏进「日均值」里让你感觉不到——代价是你也感觉不到任何真实的变化了。
实操纪律三条:单次剧烈波动不反应;下跌先复查一次再相信;永远读快照序列而不是单点。这也是为什么这个工具把每次检查都存 SQLite 而不是覆盖——历史本身就是方差证据。
发现三:GSC 说第 7,实时 SERP 说没有
拿 GSC quick-win 清单里的词对比:GSC 报均值 7-21 位,同一批词在实时匿名 SERP 的前 20 全部缺席。
两个读数都是真的,因为它们测的不是同一件事:
- GSC 的位置是均值——窗口内所有日期、所有查询变体、所有参排 URL 的平均。一周内从 #4 滑到 #12,GSC 报 #8。
- 实时快照是时点——此刻、单一市场、匿名桌面端、深度 20。波动中被抽到哪一格就是哪一格。
所以 GSC 的「第 7 位」不保证任何一次具体搜索里你排第 7。这对工作流的含义:用 GSC 找「已经有真实展示和点击的词」(这是它的强项——真实搜索聚合),用实时快照验证「正在推的那次爬升是否真的动了 SERP」。两个工具各守一层,谁也不替代谁。
成本账
17 个词每周查一次:每月约 74 次 Serper 调用,免费 2500 额度的 3%。加词线性增长——170 个词也才 30%。对个人站和小项目,这套的边际成本是零;对需要每日、多地、竞品网格的机构场景,$99/月买的是运营层的省心,那是另一笔账。
边界,诚实地讲
时点排名测量有天花板:单次快照方差大(见发现二)、匿名 SERP 不代表登录态/本地化结果、深度 20 之外的世界看不见。这套工具不适合承诺客户「你排第几」的合规场景,适合自己盯项目、验证推广动作、积累变化证据。
追踪器是包里工作流的一环:关键词研究找候选、难度评分过滤、GSC quick-win 筛出接近的、rank_tracker 盯推广有没有真动了 SERP。它也和其他工具一样挂在同一个 MCP server 上,agent 不用记 CLI 参数就能查排名——全部随开源包发布。
两个月快照换来三个认知——一次要用内链去反转的品牌词易主、一条本会误读成「排名崩了」的方差纪律、一个重新定义「第 7 位」的 GSC 落差。这比我为大多数付费仪表盘掏过的钱回报都高。
FAQ
自己跑 Python 排名追踪要花多少钱?
用 Serper.dev 免费档,个人站约等于零。每次检查每词拉一次 SERP,成本=词数×检查次数:17 个词每周查一次约 74 次调用/月,占免费 2500 次额度的 3%。工具本身纯 Python 标准库加 SQLite 存储——没有数据库服务器、没有托管、没有订阅。商业追踪器 $99/月起,贵在同一个机械内核之上加了多地追踪、定时爬虫、竞品网格和报告 PDF。
GSC 已经报排名了,为什么还要手动追?
两者测的不是同一件事,失败方式也不同。GSC 报的是窗口内所有日期、所有归并查询变体、站内所有参排 URL 的平均位置,只统计 Google 真实服务过的搜索——一个均值化、回溯性、混合口径的测量。实时追踪拉的是此刻一条匿名、单一市场、桌面端的 SERP。本文数据里 GSC 显示某词均值第 7,实时匿名 SERP 前 20 都没有这个站——两个读数都是真的。用 GSC 找有真实展示和点击的词;用实时快照盯你正在推的那次爬升——GSC 的均值会把信号摊薄到几周里。
单次排名检查可信吗?
比你希望的不可信,本文数据给了量化:同一个品牌词、同样的深度,一分钟内连续检查返回一次「不在前 20」、三次「#2」。API 返回的 SERP 会在快照间轮换,Google 本身也按机房和查询上下文变结果。实操守则:单次剧烈波动不要反应,下跌先复查再相信,读快照历史而不是任何单点——这正是追踪器把每次检查都存进 SQLite 而不是覆盖上次的原因。
数据存在哪,能直接查吗?
本地 SQLite,~/.zens_ink/ranks.db,首次使用自动建。两张表:keywords(keyword、domain、tag、created_at)和 snapshots(keyword、position、url、checked_at),关键词加时间戳有索引。因为是纯 SQLite,可以从 Python 打开、接图表库、复制文件即备份。每条 CLI 命令都支持 --json,方便接进其他工具。
能追多个域名、给关键词分组吗?
能——域名是关键词级属性,add 时用 --domain 指定,可选 --tag 分组(本文数据就混了不同站的标签)。一次 check 给所有追踪词各拉一次 SERP、各写一条快照,各自对自己的域名匹配。没有按城市 geo 追踪——gl/hl 是每次检查级的参数,默认美区英文——多市场就是换不同 --gl 分次跑。