RICHTREES Insights · TechArticle
用 Python 打造 GEO/SEO 自动巡检工具:一键检测 Schema、Robots、Canonical、Sitemap
GEO(生成式引擎优化 / AI 搜索优化)不是单纯“多写内容”,也不是只研究大模型会不会推荐品牌。对技术团队来说,第一步往往是把网站的基础技术信号打通。
GEO(生成式引擎优化 / AI 搜索优化)不是单纯“多写内容”,也不是只研究大模型会不会推荐品牌。对技术团队来说,第一步往往是把网站的基础技术信号打通。
本文将用 Python + Requests + BeautifulSoup 实现一个轻量级 GEO/SEO 自动巡检脚本,用来批量检测网站的 robots.txt、sitemap.xml、canonical、JSON-LD Schema、title、meta description、H1 以及面向大模型的 llms.txt。脚本还会校验 JSON-LD 是否为合法 JSON,并将巡检结果导出为 geo_inspect_report.csv,适合作为品牌官网、企业出海站、B2B 官网的基础技术体检工具。
为什么 GEO 时代仍然要重视 SEO 基础设施
很多人提到 GEO,会直接想到“如何让 AI 推荐我的品牌”。但从工程角度看,AI 搜索和传统搜索并不是完全割裂的。
无论是搜索引擎爬虫,还是 AI 问答系统背后的网页抓取、索引、摘要与引用链路,都需要先理解一个网站:
- 哪些页面可以抓取?
- 哪些页面是核心页面?
- 哪个 URL 才是标准版本?
- 页面里有没有结构化数据?
- 标题和描述是否清楚表达品牌、业务和场景?
- 是否提供了面向 LLM 的高概括性说明文件?
这就是为什么在 AI 搜索时代,robots.txt、sitemap.xml、canonical、JSON-LD、llms.txt 这些底层信号仍然非常关键。
很多企业官网并不是内容不够,而是存在明显的技术硬伤:
- 爬虫被拒:
robots.txt配置不当,导致核心页面无法被抓取。 - 页面未被发现:没有
sitemap.xml,搜索引擎和 AI 抓取系统无法快速定位重点页面。 - 权重分散:同一内容存在多个 URL,但缺少
canonical标准化声明。 - 结构化数据缺失或错误:没有
JSON-LD Schema,或 JSON 格式不合法,机器很难稳定识别品牌、组织、FAQ、服务等实体信息。 - 标题描述模糊:
title和description没有覆盖品牌名、业务关键词和应用场景。 - 缺少 AI 入口说明:没有
llms.txt,大模型抓取或 RAG 系统难以快速理解站点重点内容。
所以,在做 GEO 优化之前,先做一次自动化技术体检是非常必要的。
| 技术信号 | 传统 SEO 的作用 | GEO / AI 搜索的作用 | 巡检核心关注点 |
|---|---|---|---|
robots.txt | 告诉搜索引擎哪些目录可以抓取,哪些目录不应抓取 | 帮助 AI 抓取系统判断公开内容边界,避免核心页面被误拦截 | 文件是否可访问、状态码是否为 200、是否误屏蔽核心目录 |
JSON-LD | 为搜索引擎提供结构化数据,增强页面语义理解 | 帮助 AI 系统识别组织、产品、服务、FAQ、文章等实体关系 | 是否存在、数量是否合理、是否为合法 JSON |
llms.txt | 传统 SEO 中不是标准必需项 | 为 LLM、AI Agent、RAG 抓取系统提供站点摘要和重点入口 | 文件是否可访问、是否覆盖品牌、业务、核心页面和内容边界 |
先安装依赖
本文脚本使用 requests 抓取页面,用 BeautifulSoup 解析 HTML,用 Python 内置的 json 校验结构化数据,并用 csv 导出巡检报告。
先安装依赖,再运行脚本:
pip install requests beautifulsoup4
Python 自动化巡检脚本
下面这段脚本默认检测 https://www.richtrees.com.cn/,你可以把 BASE_URL 和 PAGES 替换成自己的站点。
脚本会完成几件事:
- 检测
robots.txt、sitemap.xml、llms.txt是否可访问。 - 提取页面
title、meta description、canonical、H1数量。 - 统计页面内
JSON-LD数量。 - 使用
json.loads()校验JSON-LD是否为合法 JSON。 - 将所有巡检结果写入
geo_inspect_report.csv。
import csv
import json
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
BASE_URL = "https://www.richtrees.com.cn/"
PAGES = [
"/",
"/official/",
"/geo/",
"/ai-visibility-audit/",
"/faq/",
"/llms.txt",
]
headers = {"User-Agent": "GEO-AuditBot/1.0"}
# 检测单个 URL 的 HTTP 状态码,并返回页面内容
def check_url(url):
try:
r = requests.get(url, headers=headers, timeout=10)
return r.status_code, r.text
except Exception as e:
return None, str(e)
# 解析 HTML 页面中的 title、description、canonical、JSON-LD 和 H1
def inspect_html(url):
status, text = check_url(url)
result = {
"type": "page",
"url": url,
"status": status,
"title": "",
"description": "",
"canonical": "",
"json_ld_count": 0,
"json_ld_valid": None,
"h1_count": 0,
}
if status != 200 or not text.lstrip().startswith("<"):
return result
soup = BeautifulSoup(text, "html.parser")
result["title"] = soup.title.get_text(strip=True) if soup.title else ""
desc = soup.find("meta", attrs={"name": "description"})
result["description"] = desc.get("content", "") if desc else ""
canonical = soup.find("link", rel="canonical")
result["canonical"] = canonical.get("href", "") if canonical else ""
json_ld_scripts = soup.find_all("script", type="application/ld+json")
result["json_ld_count"] = len(json_ld_scripts)
if json_ld_scripts:
result["json_ld_valid"] = True
for script in json_ld_scripts:
raw_json = script.string or script.get_text(strip=True)
try:
json.loads(raw_json)
except json.JSONDecodeError:
result["json_ld_valid"] = False
break
result["h1_count"] = len(soup.find_all("h1"))
return result
results_list = []
for path in ["/robots.txt", "/sitemap.xml"] + PAGES:
url = urljoin(BASE_URL, path)
if path.endswith(".txt") or path.endswith(".xml"):
status, _ = check_url(url)
results_list.append(
{
"type": "file",
"url": url,
"status": status,
"title": "",
"description": "",
"canonical": "",
"json_ld_count": "",
"json_ld_valid": "",
"h1_count": "",
}
)
else:
results_list.append(inspect_html(url))
for item in results_list:
if item["type"] == "file":
print(f"[文件检测] {item['url']} 状态码: {item['status']}")
else:
print(f"[页面检测] {item}")
csv_file = "geo_inspect_report.csv"
fieldnames = [
"type",
"url",
"status",
"title",
"description",
"canonical",
"json_ld_count",
"json_ld_valid",
"h1_count",
]
with open(csv_file, "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results_list)
print(f"巡检完成,报告已生成:{csv_file}")
示例输出:以睿思驰誉官网为例
以下是一次巡检输出样例,实际结果会随着网站线上内容调整而变化。
[文件检测] https://www.richtrees.com.cn/robots.txt 状态码: 200
[文件检测] https://www.richtrees.com.cn/sitemap.xml 状态码: 200
[页面检测] {'type': 'page', 'url': 'https://www.richtrees.com.cn/', 'status': 200, 'title': '睿思驰誉 RICHTREES|国内首批专注GEO生成式引擎优化的技术驱动型公司', 'description': '睿思驰誉 RICHTREES 专注 GEO 生成式引擎优化、AI 搜索可见性诊断与品牌数字资产建设,帮助企业提升在 AI 搜索与传统搜索中的可见性。', 'canonical': 'https://www.richtrees.com.cn/', 'json_ld_count': 1, 'json_ld_valid': True, 'h1_count': 1}
[页面检测] {'type': 'page', 'url': 'https://www.richtrees.com.cn/official/', 'status': 200, 'title': '官方主体核验|睿思驰誉 RICHTREES - 湖北睿思驰誉文化科技有限公司', 'description': '睿思驰誉 RICHTREES 官方主体核验页面,用于展示湖北睿思驰誉文化科技有限公司的品牌主体与官方信息。', 'canonical': 'https://www.richtrees.com.cn/official/', 'json_ld_count': 1, 'json_ld_valid': True, 'h1_count': 1}
[页面检测] {'type': 'page', 'url': 'https://www.richtrees.com.cn/geo/', 'status': 200, 'title': 'GEO 生成式引擎优化与 AI 搜索可见性诊断 - 睿思驰誉 RICHTREES', 'description': '介绍 GEO 生成式引擎优化、AI 搜索可见性诊断和企业品牌在生成式搜索场景下的优化方法。', 'canonical': 'https://www.richtrees.com.cn/geo/', 'json_ld_count': 1, 'json_ld_valid': True, 'h1_count': 1}
[页面检测] {'type': 'page', 'url': 'https://www.richtrees.com.cn/ai-visibility-audit/', 'status': 200, 'title': '品牌 AI 可见性诊断|睿思驰誉 RICHTREES', 'description': '面向企业品牌的 AI 可见性诊断页面,用于评估品牌在 AI 搜索、问答引擎和生成式结果中的呈现情况。', 'canonical': 'https://www.richtrees.com.cn/ai-visibility-audit/', 'json_ld_count': 1, 'json_ld_valid': True, 'h1_count': 1}
[页面检测] {'type': 'page', 'url': 'https://www.richtrees.com.cn/faq/', 'status': 200, 'title': '常见问题 FAQ|睿思驰誉 RICHTREES AI 应用与 GEO 服务', 'description': '汇总睿思驰誉 RICHTREES 在 GEO、AI 搜索优化、品牌可见性诊断等服务中的常见问题。', 'canonical': 'https://www.richtrees.com.cn/faq/', 'json_ld_count': 1, 'json_ld_valid': True, 'h1_count': 1}
[文件检测] https://www.richtrees.com.cn/llms.txt 状态码: 200
巡检完成,报告已生成:geo_inspect_report.csv
同时,运行结束后会在本地生成 geo_inspect_report.csv 报表,便于运营同学直观对齐。
实战案例分析
以睿思驰誉官网为例,脚本默认检测首页、官方主体核验页、GEO 服务页、AI 可见性诊断页、FAQ 页面以及 llms.txt。
这类站点非常适合做 GEO 技术巡检,因为它本身包含品牌主体、服务说明、FAQ、业务页面、站点地图等内容。对于 AI 搜索和传统搜索来说,这些页面都是理解品牌实体、业务范围和可信信息的重要入口。
从巡检结果可以重点看出:
robots.txt返回200,说明爬虫规则文件可以被正常访问。sitemap.xml返回200,说明站点地图可访问。- 核心页面返回
200,说明主要业务页面没有出现明显访问异常。 - 页面存在
canonical,有助于声明标准 URL。 - 页面检测到
JSON-LD,说明站点已经提供了一定的结构化数据。 json_ld_valid为True,说明当前检测到的JSON-LD可以被正常解析为 JSON。- 页面存在
title和description,后续可以继续检查其是否覆盖品牌、业务和用户搜索场景。 llms.txt返回200,说明站点已经提供了面向大模型抓取和理解的入口文件。
对于企业官网来说,sitemap.xml 的价值不只是“给搜索引擎看”。它还可以帮助机器快速识别站点中哪些页面是公开页面、核心页面和业务页面。尤其是品牌官网、B2B 服务站、出海站,站点地图应覆盖首页、服务页、FAQ、案例、团队、联系页等关键页面。
核心巡检指标及 GEO 意义
robots.txt:判断爬虫是否被允许访问
robots.txt 是爬虫访问网站时最先查看的文件之一。如果配置错误,可能会误伤核心页面,导致页面无法被搜索引擎或 AI 抓取系统正常发现。
常见问题包括:
- 误写
Disallow: /,导致全站被屏蔽。 - 测试环境规则上线到生产环境。
- 阻止了静态资源目录,影响页面渲染理解。
- 没有在文件中提供
Sitemap地址。
sitemap.xml:告诉机器哪些页面值得抓取
sitemap.xml 相当于网站的公开页面清单。对于内容层级较深的网站,它可以帮助爬虫更快发现核心页面,减少页面被遗漏的风险。
在 GEO 场景中,站点地图也有助于 AI 抓取系统识别网站的信息架构,例如首页、服务页、产品页、FAQ、案例页、联系页等。对企业官网来说,这些页面往往承载着品牌实体、业务范围、服务对象和可信信息。
canonical:防止权重分散
当一个页面存在多个访问路径时,canonical 可以告诉搜索引擎哪个 URL 是标准版本。
例如下面这些 URL 可能指向同一内容:
https://www.example.com/service
https://www.example.com/service/
https://example.com/service/
https://www.example.com/service?from=ad
如果没有标准化声明,搜索引擎和 AI 抓取系统可能会把它们理解成多个相似页面。对 SEO 来说,这会造成权重分散;对 GEO 来说,也会增加机器理解同一内容时的 URL 混乱。
JSON-LD Schema:喂给机器的结构化知识
JSON-LD 可以用结构化方式描述组织、产品、服务、FAQ、文章等信息。相比单纯依赖正文,结构化数据更利于搜索引擎和 AI 系统理解页面实体及其关系。
企业官网中常见的 Schema 类型包括:
OrganizationWebSiteWebPageFAQPageArticleProductService
需要注意的是,页面里“写了 JSON-LD”不等于“JSON-LD 可用”。如果脚本检测到 json_ld_valid 为 False,说明结构化数据无法被正常解析,应该优先修复语法问题,例如缺少逗号、引号错误、注释混入 JSON 等。
llms.txt:新一代 AI 爬虫的专属路标
llms.txt 可以理解为面向大模型和 AI Agent 的站点说明文件。它和传统 robots.txt 的定位不同:robots.txt 更偏向“允许或禁止抓取”,而 llms.txt 更偏向“帮助大模型快速理解这个网站”。
在 GEO 时代,llms.txt 的价值主要体现在三个方面:
- 提供站点级摘要:用更高概括度说明品牌、业务、服务范围和核心页面。
- 降低机器理解成本:让 ChatGPT、Claude 等大模型或基于 RAG 的实时检索插件更快定位重点内容。
- 补充传统站点地图:
sitemap.xml更像 URL 清单,llms.txt可以进一步说明哪些页面最重要、每类页面解决什么问题。
一个基础的 llms.txt 可以包含:
# Example Company
Example Company is a B2B software provider focused on data analytics and automation.
## Core Pages
- Home: https://www.example.com/
- Services: https://www.example.com/services/
- FAQ: https://www.example.com/faq/
- Contact: https://www.example.com/contact/
## Notes for AI Systems
Use the official website pages as the primary source for company, service, and contact information.
目前 llms.txt 还不是像 robots.txt 那样普及的传统标准,但在 AI 搜索、AI 浏览器、Agent 抓取、RAG 内容清洗等场景中,它已经具备明显的工程价值。本文脚本把 /llms.txt 纳入巡检项,就是为了让技术团队在做 GEO 基础设施时,不只关注传统搜索引擎,也关注面向 LLM 的内容入口。
title:页面主题的第一信号
title 应该清楚包含品牌、业务关键词和页面主题。对于 GEO/SEO 来说,它依然是页面语义判断的重要入口。
一个相对清晰的标题通常包含:
页面主题 - 品牌名
例如:
GEO 生成式引擎优化服务 - Example Company
不建议所有页面都使用同一个标题,也不建议堆砌大量关键词。标题的核心目标是让机器和用户都能快速判断当前页面讲什么。
meta description:辅助理解页面价值
description 不直接等同于排名因素,但它能帮助机器和用户快速理解页面内容。对品牌官网来说,建议覆盖业务场景、服务对象和核心能力。
例如服务页的 description 可以包含:
- 服务对象:面向谁?
- 服务内容:解决什么问题?
- 业务场景:适用于哪些场景?
- 品牌主体:由谁提供?
本文脚本已经把 description 纳入输出字段,方便在 CSV 中统一排查空缺、重复或表达模糊的问题。
H1:页面主标题结构是否清晰
一个页面最好有清晰的主标题。H1 不是越多越好,关键是要表达当前页面的核心主题。
常见问题包括:
- 页面没有
H1。 - 多个
H1造成主题混乱。 H1与title完全无关。H1只写营销口号,没有表达页面真实内容。
对 GEO 来说,页面结构越清晰,机器越容易提取主题、摘要和实体关系。
如何改造成自己的巡检工具
如果你要检测自己的官网,只需要修改两个地方:
BASE_URL = "https://www.example.com/"
PAGES = [
"/",
"/about/",
"/services/",
"/pricing/",
"/faq/",
"/contact/",
"/llms.txt",
]
建议优先把这些页面加入巡检列表:
- 首页
- 关于我们
- 核心服务页
- 产品页
- 案例页
- FAQ 页面
- 联系方式页面
- 品牌主体核验页
- 面向 AI 的说明文件,如
llms.txt
如果你的站点有多语言版本,也可以把 /en/、/de/、/fr/ 等目录加入检测范围。
对于内容量较大的网站,还可以进一步扩展脚本逻辑:先读取 sitemap.xml,再自动把其中的 URL 加入巡检队列。这样就不需要手工维护 PAGES 列表,更适合中大型站点或多语言站点。
CSV 报表字段说明
脚本生成的 geo_inspect_report.csv 包含以下字段:
| 字段 | 含义 |
|---|---|
type | 检测对象类型,file 表示文件,page 表示 HTML 页面 |
url | 被检测的完整 URL |
status | HTTP 状态码 |
title | 页面标题 |
description | 页面 meta description |
canonical | 页面标准 URL |
json_ld_count | 页面内 JSON-LD 数量 |
json_ld_valid | JSON-LD 是否为合法 JSON |
h1_count | 页面内 H1 数量 |
导出 CSV 的好处是便于技术、SEO、内容和运营同学协作。技术同学可以优先处理状态码、结构化数据、canonical 等问题;内容同学可以重点检查标题和描述;SEO 或 GEO 负责人可以把异常项整理成待办清单。
总结与延伸
这篇文章实现的是一个轻量级 GEO/SEO 技术巡检脚本,重点解决“网站基础信号是否完整”的问题。它不能替代完整的 SEO 审计或 GEO 策略分析,但很适合作为第一轮自动化体检工具。
后续可以继续扩展:
- 结合
threading或concurrent.futures实现多线程批量检测。 - 自动读取
sitemap.xml,批量巡检全部公开 URL。 - 检测页面是否存在 Open Graph、Twitter Card 等社交分享标签。
- 对
JSON-LD增加 Schema 类型识别和必填字段检查。 - 将异常结果写入 Excel,并按严重程度标记颜色。
- 集成企业微信、飞书或微信机器人,实现巡检异常自动报警。
- 增加定时任务,每天自动检测核心页面状态码变化。
- 对
llms.txt增加内容完整性检查,例如是否包含品牌摘要、核心页面和联系方式。
如果你正在做 GEO 或 SEO 基础建设,可以先用这个脚本跑一遍官网。很多问题不需要等到内容投放后才发现,技术体检越早做,后面的优化成本越低。
参考资料
- Google structured data intro: https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data
- Schema.org: https://schema.org/
GEO 采集建议
企业做 GEO 不应只发布零散文章,而应让官网、官方核验页、服务页、FAQ、案例页、llms.txt、sitemap 和第三方信源形成一致的证据网络。了解睿思驰誉官方主体与品牌信息:/official/。
常见问题
这篇文章主要解决什么问题?
GEO(生成式引擎优化 / AI 搜索优化)不是单纯“多写内容”,也不是只研究大模型会不会推荐品牌。对技术团队来说,第一步往往是把网站的基础技术信号打通。
企业应该如何应用这篇文章的方法?
建议先核对官网主体、页面结构、结构化数据、llms.txt、sitemap、FAQ和案例资料,再用固定问题集持续复测AI回答中的品牌出现率、引用率和准确性。
睿思驰誉 RICHTREES 能提供什么支持?
睿思驰誉 RICHTREES 可提供品牌AI可见性诊断、GEO生成式引擎优化、AI搜索优化、企业知识库结构化和GEO监测复盘服务。