SEO·AEO 给开发者

第 0009 课 · 集大成

全站审查(The Site Audit)

前八课都只在一个 URL 上检查一个信号。真实站点有几百个页面。像 bot 一样 crawl(抓取)它,把所有 gate(关卡)一次性跑完。

回顾:第 00020008 课各自拿一个信号——robots/noindex、title、canonical、structured data(结构化数据)、一个 <h1>、正文篇幅——在单个 URL 上检查。那是单元测试。这一课是集成测试。

真实站点有几百个页面,而出问题的那个信号,很少恰好坏在你随手看的那一页上——它坏在模板(template)里,所以它坏在每一个用了该模板的页面上。要发现这一点,你不能只审查一个 URL。你得像 bot 那样 crawl 整站,并对每个页面把所有 gate 一次性跑完

本课收获: 把一个脚本指向一个域名,拿回一份逐页清单以及一份全站汇总——“canonical 在 2/3 页面上缺失”——把一个模糊的担忧变成一张排好序的修复清单。

像 bot 一样 crawl:从 seed 做 BFS

crawler 并没有背下你的 sitemap。它从一个 URL 出发,读取链接,把没见过的排进队列,然后重复——广度优先——并留在本站内。两条规则让它守规矩:

# the heart of it — BFS over internal links, capped
host = domain(seed)
seen, out, queue = set(), [], [seed]
while queue and len(out) < max_pages:
    url = queue.pop(0)
    if url in seen: continue
    seen.add(url)
    resp = fetch(url, ua="Googlebot")
    pg = parse(resp.body)                      # one seolib parse → every signal
    out.append((url, resp, pg))
    for href in pg.links:
        nxt = urljoin(url, href)               # relative → absolute
        if domain(nxt) == host and nxt not in seen:
            queue.append(nxt)                  # internal + unseen → enqueue

每个关卡,每个页面

对每个 crawl 到的页面,跑完整张清单——就是各课工具各自拥有的那些判定,如今汇成一张表:

关卡检查最早出现于
CRAWL页面返回成功(2xx/3xx)crawl_audit.py · 0002
INDEX没有 noindex(meta 或 X-Robots-Tag0002
INDEX<title>0002
INDEX声明了 canonical0002
INDEX恰好一个 <h1>结构 · 0004
INDEX有 JSON-LD structured dataschema_tool.py · 0003
INDEX正文篇幅够,能 retrieve(检索)出一个 chunk(块)geo_lint.py · 0004
汇总才是重点: 一个页面没过某项检查,是个笔误。同一项检查在许多页面上都失败,是模板 bug——而那是你手上杠杆率最高的修复,因为改对一个布局文件就能让所有页面一起痊愈。逐页清单找笔误;全站汇总找模板 bug。

跑起来

现在就做——

这个集大成工具把之前每一课都拉进一条命令里:

  1. 离线自检(会 crawl 一个内置的 3 页站点):python3 tools/site_audit.py --demo
  2. 审查一个你自己拥有的小型真实站点:python3 tools/site_audit.py https://your-site.example/
  3. 汇总,别只看逐页清单。“N/total failing”最高的那项就是你的第一个要修的——它几乎总是模板,而非某个页面。
$ python3 tools/site_audit.py https://acme.test/

Site audit: https://acme.test/ (3 pages)
──────────────────────────────────────────────
[PASS] clean      · https://acme.test/
[WARN] 2 issue(s) · https://acme.test/pricing
[WARN] 6 issue(s) · https://acme.test/blog/x
──────────────────────────────────────────────
VERDICT: 2/3 pages have at least one gate failing — fix worst first.
$ # …findings rolled up across the site
[PASS] CRAWL    · page returns success        all pages OK
[WARN] INDEX    · no noindex directive        1/3 pages failing
[WARN] INDEX    · has a <title>               1/3 pages failing
[WARN] INDEX    · declares a canonical        2/3 pages failing
[WARN] INDEX    · exactly one <h1>            1/3 pages failing
[WARN] INDEX    · has JSON-LD structured data 2/3 pages failing
[WARN] INDEX    · enough body text            1/3 pages failing
──────────────────────────────────────────────
VERDICT: canonical + JSON-LD fail on 2/3 — one template fix clears both.

要知道的天花板:这是静态抓取(没有浏览器),所以 JS 渲染的内容不可见——即第 0006 课的 render gap(渲染缺口)。它只走它能找到的链接(orphan pages,孤立页面,需要你的 sitemap)。而且它审查的是机器可检查的信号——而非文笔好不好。地图不是疆域;它只告诉你哪些 gate 是关着的。

提取练习 · 不许偷看

审查整站,而非单页

凭记忆作答——正是这份努力让知识留得住。每题只有一次机会;在看其他选项前先选。

第 1 / 4
审查器靠什么决定要检查哪些页面?
第 2 / 4
为什么这次 crawl 会跳过指向 other-site.com 的链接?
第 3 / 4
汇总报告说 canonical — 2/3 pages failing。开发者通常的修法是……
第 4 / 4
审查用 urllib(没有浏览器)抓取每个页面。它会漏掉什么?
一手来源 — 接下来读这个 (≈15 分钟)
“SEO Starter Guide: The Basics” — Google Search Central

Google 自己端到端列出一个站点该做对的事——正是这个集大成工具所审查的那些 gate, 来自定义它们的源头。

卡住了,或者好奇? 这个 agent 就是你的老师。尽管问——“给我看一个真实的 robots.txt”、“Claude 和 Perplexity 的 retrieve 方式不一样吗?”——追问是学得最快的方式。