hreflang 审计工具:外贸多语言站谷歌SEO的隐性杀手
做外贸独立站,做英语站、德语站、法语站是常态。多语言站有个专门负责「告诉谷歌哪个版本给哪个地区」的标签,叫 hreflang。它写对了,德国买家搜到的是德语版,美国买家搜到的是英语版;写错了,谷歌可能把错版本推给用户,或者干脆忽略掉,几个版本自己互相打架。
hreflang 的坑很多:标签缺失、缺 x-default、语言代码写错、双向引用没对上、指向的 URL 打不开。人工一个个页面查,费时又容易漏。这篇用 Python 写一个审计工具,把这些检查全自动化,跑一遍就出报告。
hreflang 的官方规则可以看 Google 搜索中心的说明:本地化版本(hreflang) 和 管理多地区与多语言网站。
工具能检查什么
- 提取页面上所有
hreflang标签 - 校验语言代码格式(
en/de/fr/zh-CN这类) - 检查是否缺少
x-default - 并发检查每个版本 URL 是否可访问(HTTP 200)
- 并发检查双向引用是否闭环
- 输出问题清单
依赖:requests、beautifulsoup4。
完整代码
python
# -*- coding: utf-8 -*-
"""
hreflang 标签审计工具
用途:检查外贸多语言独立站的 hreflang 标签是否规范、可访问、双向引用闭环
依赖:pip install requests beautifulsoup4
"""
import re
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor, as_completed
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0 Safari/537.36",
}
# 合法语言代码:en / de / fr / es / pt / zh-CN / zh-TW 这类
LANG_RE = re.compile(r"^[a-z]{2,3}(-[A-Za-z]{2,4})?$")
def fetch_html(url, timeout=10):
"""请求页面,返回 (status_code, html)"""
try:
resp = requests.get(url, headers=HEADERS, timeout=timeout, allow_redirects=True)
return resp.status_code, resp.text
except requests.RequestException as e:
return None, str(e)
def extract_hreflang(url, html):
"""提取页面上的 hreflang 映射:{lang: 绝对URL}"""
soup = BeautifulSoup(html, "html.parser")
mapping = {}
for link in soup.find_all("link", rel=lambda v: v and "alternate" in v):
hreflang = link.get("hreflang")
href = link.get("href")
if hreflang and href:
mapping[hreflang.lower()] = urljoin(url, href)
return mapping
def check_lang_code(mapping):
problems = []
for lang in mapping:
if lang != "x-default" and not LANG_RE.match(lang):
problems.append(f"语言代码格式异常: {lang!r},应为 en / zh-CN 这类格式")
return problems
def check_accessibility(mapping):
problems = []
def worker(item):
lang, u = item
code, _ = fetch_html(u)
return lang, u, code
with ThreadPoolExecutor(max_workers=8) as ex:
futures = {ex.submit(worker, item): item for item in mapping.items()}
for fut in as_completed(futures):
lang, u, code = fut.result()
if code != 200:
problems.append(f"[{lang}] 无法访问 (HTTP {code}): {u}")
return problems
def check_reciprocal(entry_url, entry_lang, mapping):
problems = []
def worker(item):
lang, u = item
code, html = fetch_html(u)
if code != 200:
return None
back = extract_hreflang(u, html)
if back.get(entry_lang) != entry_url:
return f"[{lang}] 页面没有正确回指 {entry_lang} 版本: {u}"
return None
targets = [(l, u) for l, u in mapping.items() if l != "x-default"]
with ThreadPoolExecutor(max_workers=8) as ex:
futures = [ex.submit(worker, t) for t in targets]
for fut in as_completed(futures):
res = fut.result()
if res:
problems.append(res)
return problems
def audit(url):
print(f"目标页面: {url}\n" + "=" * 60)
code, html = fetch_html(url)
if code != 200:
print(f"页面无法访问 (HTTP {code})")
return
mapping = extract_hreflang(url, html)
if not mapping:
print("[问题] 页面没有任何 hreflang 标签,请先补上")
return
print(f"发现 {len(mapping)} 个 hreflang 版本:")
for lang, u in sorted(mapping.items()):
print(f" {lang:12s} -> {u}")
# 本页语言 = 自引用那条的 hreflang
entry_lang = next((l for l, u in mapping.items() if l != "x-default" and u == url), None)
print("\n[1] 语言代码检查")
lang_problems = check_lang_code(mapping)
if not lang_problems:
print(" 全部合法")
for p in lang_problems:
print(" ", p)
if "x-default" not in mapping:
print(" [建议] 缺少 x-default,加一条兜底给未匹配语言的访客")
print("\n[2] 可访问性检查(并发)")
acc_problems = check_accessibility(mapping)
if not acc_problems:
print(" 全部可访问 (HTTP 200)")
for p in acc_problems:
print(" ", p)
print("\n[3] 双向引用检查(并发)")
if not entry_lang:
print(" [警告] 没找到自引用,无法判断本页语言,请人工确认")
else:
print(f" 本页语言判定为: {entry_lang}")
rec_problems = check_reciprocal(url, entry_lang, mapping)
if not rec_problems:
print(" 双向引用闭环正常")
for p in rec_problems:
print(" ", p)
print("\n" + "=" * 60)
print("审计结束。有问题的地方,对照 Google 官方文档修正即可。")
if __name__ == "__main__":
audit("https://example.com/en/products/")
怎么用
bash
pip install requests beautifulsoup4
把最后一行 audit(...) 里的 URL 换成你自己的页面,运行即可。
输出会分三块:语言代码检查、可访问性检查、双向引用检查。每一块有问题都会单独列出,对着改就行。
几个容易忽略的点
hreflang 是双向的。 A 页面声明了 B 的德语版,B 页面也必须回指 A 的英语版,缺一边谷歌就可能不认。这就是工具里「双向引用检查」在做的。
x-default 建议保留。 它用来兜底:当访问者的语言和地区跟任何版本都匹配不上时,跳到哪个页面。多数站点指向英文版或一个语言选择页。
语言代码要规范。 en 表示英语,zh-CN 表示简体中文,zh-TW 表示繁体中文。别写 en-US 去表示英语全站,那会被理解成「美国英语」,跟地区语义混在一起。
写在最后
工具代码可以直接拿去用,跑一遍就知道自己的多语言站 hreflang 有没有问题。觉得有用欢迎点赞、收藏、转发,有疑问评论区留言或私信交流。