SEO 巡检不能只看一个分数。页面加载变慢、Canonical 配置错误、DNS 记录漂移、证书临近到期,都会影响搜索引擎访问和用户体验,但它们属于完全不同的问题域。如果把所有信号混成一个“站点健康分”,报告看起来完整,却很难指导修复。
更实用的做法,是把巡检拆成三层:
本文使用 网页性能与 SEO 评分、DNS 查询、SSL 证书解析 和 WHOIS 查询,搭建一条可定时执行、可追踪、不过度告警的网站巡检管线。
同一个站点可以有几十个重点 URL ,但通常只对应一个主域名。页面评分应按 URL 执行,DNS 、SSL 、WHOIS 则应按域名去重执行,最后再汇聚成报告。
这条数据流有两个关键边界:页面结果不能代替域名状态,域名异常也不能直接伪装成页面 SEO 评分失败。两类检查分别保留原始状态,规则层只负责解释和分级。
| 检查范围 | 接口 | 主要结果 | 适合回答的问题 |
|---|---|---|---|
| URL | PageSpeed | 四类评分、FCP 、LCP 、TBT 、CLS 、SEO 审计、TopIssues | 页面是否变慢,标题、Canonical 、robots.txt 、viewport 是否存在明显问题 |
| 域名 | DNS | A 、AAAA 、CNAME 、MX 、TXT 、NS 、SOA 等记录 | 解析记录是否符合预期,是否发生未经确认的变化 |
| 域名 | SSL | 证书链、有效期、主机与诊断信息 | 证书是否有效,是否接近到期,主机名是否匹配 |
| 域名 | WHOIS | 注册时间、到期时间、注册商、名称服务器等 | 域名注册信息是否可用,重要日期是否需要提醒 |
WHOIS 字段可能受注册局和隐私保护影响。字段缺失应标记为“未知”,不能直接判定为域名故障。
巡检任务的输入不是一个模糊的“站点”,而是两组明确目标:
from urllib.parse import urlsplit
def normalize_target(page_url: str) -> tuple[str, str]:
parsed = urlsplit(page_url)
if parsed.scheme not in {"http", "https"} or not parsed.hostname:
raise ValueError("A valid HTTP or HTTPS URL is required")
hostname = parsed.hostname.encode("idna").decode("ascii")
normalized_url = parsed._replace(fragment="").geturl()
return normalized_url, hostname
不要用字符串切割域名。真实 URL 可能包含端口、国际化域名、IPv6 或路径中的相似文本。
PageSpeed 接口当前使用 GET /websitetools/pagespeed-score,支持 mobile 与 desktop 两种策略,默认是 mobile。一次请求可以返回:
新接入建议把 AppKey 保存在服务端环境变量中,并通过 Header 传递:
import json
import os
from urllib.parse import urlencode
from urllib.request import Request, urlopen
def fetch_pagespeed(page_url: str) -> dict:
query = urlencode({
"url": page_url,
"strategy": "mobile",
"locale": "zh-CN",
"categories": "performance,accessibility,best-practices,seo",
"forceRefresh": "false",
})
request = Request(
f"https://api.gugudata.com/websitetools/pagespeed-score?{query}",
headers={"X-GUGUDATA-APPKEY": os.environ["GUGUDATA_APPKEY"]},
method="GET",
)
with urlopen(request, timeout=60) as response:
payload = json.load(response)
data_status = payload.get("DataStatus", {})
if int(data_status.get("StatusCode", 0)) != 100:
message = data_status.get("StatusDescription", "PageSpeed failed")
raise RuntimeError(message)
return payload.get("Data", {})
HTTP 200 只说明请求得到响应,不能替代业务状态判断。生产实现还要捕获超时和非 2xx 状态,并限制响应体大小。
三个域名接口当前都是 GET 请求:
/v2/websitetools/dns-lookup
/v2/websitetools/sslcertinfo
/v2/websitetools/whois
它们与 PageSpeed 存在一个容易踩坑的契约差异:
| 接口类型 | 状态对象 | 当前成功值 |
|---|---|---|
| PageSpeed | DataStatus.StatusCode |
100 |
| DNS 、SSL 、WHOIS v2 | dataStatus.statusCode |
200 |
因此,不能把 PageSpeed 的校验器直接复制给 v2 域名接口:
def require_v2_success(payload: dict) -> dict:
data_status = payload.get("dataStatus", {})
if int(data_status.get("statusCode", 0)) != 200:
message = data_status.get("statusDescription", "Domain check failed")
raise RuntimeError(message)
return payload.get("data", {})
聚合层可以把两类结果统一映射为 success、failed 或 unknown,但必须同时保留原始状态字段和采集时间,避免统一过程中丢失排错依据。
巡检系统最难的部分不是请求接口,而是决定哪些信号需要立即处理。建议先识别可用性或安全硬故障,再排除缓存过期和计划内变更,最后比较历史基线。
这套决策逻辑把结果分为三类:
固定分数线通常不适合所有站点。更可靠的比较条件是同一 URL 、相同检测策略、相近采集条件下的历史变化。
| 原始信号 | 容易产生的误判 | 建议动作 |
|---|---|---|
| Performance 或 SEO 分数下降 | 页面已经故障 | 查看 TopIssues 、最终 URL 、缓存标记,并与同策略基线比较 |
| DNS 记录变化 | 解析一定错误 | 与预期记录和计划变更窗口核对 |
| SSL 证书接近到期 | 网站已经不可访问 | 生成到期提醒,核对自动续期状态和证书链 |
| WHOIS 字段为空 | 域名异常 | 标记数据缺口,考虑隐私保护与注册局差异 |
行动项至少应包含目标、问题类型、严重度、首次发现时间、连续次数、证据摘要、负责人和下一步。没有明确责任人与动作的问题,只是一条日志。
PageSpeed 返回 Cached 和 FetchTime。如果报告只展示“任务在 10:00 执行”,读者可能误以为所有页面都在 10:00 重新检测。
建议分别保存:
scheduled_at:任务计划执行时间;collected_at:本次响应时间;fetch_time:评分报告实际生成时间;cached:是否复用了近期结果;strategy:mobile 或 desktop ;report_version:报告版本。常规巡检不应默认对全部页面使用 forceRefresh=true。关键页面出现异常时,可以由受控复核任务请求刷新。本文没有验证具体缓存窗口和刷新成本,因此不提供固定刷新间隔。
PageSpeed 可能成功,而 WHOIS 因字段不可用只返回部分信息; DNS 查询也可能失败,但页面仍然能够访问。一轮巡检最好支持以下状态:
| 状态 | 含义 |
|---|---|
| complete | 计划内检查均得到可用结果 |
| partial | 至少一项成功,至少一项失败或未知 |
| failed | 没有获得可用检查结果 |
| stale | 只有超过时效要求的历史结果 |
报告必须展示每个子检查的独立状态。新的临时失败也不应覆盖上一轮仍在有效期内的成功结果。
建议按以下顺序组织报告:
不要把完整 WHOIS 响应无差别复制到普通报告。它可能包含联系信息,应只保留支持业务判断的必要摘要,并按权限控制原始响应。
通常不需要。先按页面价值分层,常规任务记录缓存状态和真实数据时间;关键页面异常时再进行受控刷新。
不代表。它们属于域名层信号。报告可以提升其优先级,但不能伪造 PageSpeed 结果。
硬故障可以即时处理;普通波动更适合结合历史基线、连续次数、变化幅度和页面重要性判断。
通常不需要。页面检查按 URL 执行,DNS 、SSL 、WHOIS 按标准化域名去重执行,再在报告阶段关联。
SEO 自动巡检的目标不是制造更多分数,而是把页面、域名和历史变化组织成一份有证据、有人负责、能够执行的行动清单。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.