本地服务页 Schema 字段纠错清单:LocalBusiness 最容易写错的字段与官方校验工具的正确用法

2026-09-16 02:22:17 20 次浏览
LocalBusinessSchema校验结构化数据本地服务JSON-LD

一、为什么本地服务页的 Schema 错得格外多

本地服务类页面的结构化数据,本质上是把"一家店"翻译给机器听:名称、地址、营业时间、服务范围、价格区间、评价。翻译得准,AI 引擎就能在用户问"附近哪家店周日开门""XX 区域有没有上门修空调的"时把这家店推荐出去;翻译错一个字段,轻则不引用,重则把错误信息播报给用户——比如把歇业的店标成营业中。

我们审计过几十个本地服务站点和商户页,结论是:LocalBusiness 相关的 Schema 错误率远高于 Article 或 Product,而且大部分错误集中在固定的十来个字段上。这些错误多数不是"不会写",而是对规范条文的细节理解有偏差。这篇就是一份纠错清单,逐项对照官方规范说明错在哪、怎么改。

二、八个高频错误字段

2.1 address:把结构化地址塞进一个字符串

最常见错误是用一个自由文本字符串表达地址。官方规范要求 address 使用 PostalAddress 类型,省、市、区县、街道逐级拆分:

{
  "@context": "https://schema.org",
  "@type": "HomeAndConstructionBusiness",
  "name": "Example 家电维修(湖心路店)",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "湖心路 128 号 3 幢 101 室",
    "addressLocality": "泉州市",
    "addressRegion": "福建省",
    "postalCode": "362000",
    "addressCountry": "CN"
  }
}

为什么这么较真:AI 引擎做"附近"类推荐时,需要把地址解析成地理坐标参与召回。整体字符串的解析成功率明显低于结构化字段,尤其在行政区划与街道名重名的情况下(比如"建设路"遍布全国),缺一个 addressLocality 就可能导致定位到另一个城市。

2.2 openingHoursSpecification:时间格式与公共假日

第二高频错误是营业时间。常见坑有三个:用 opens/closes 却不带 dayOfWeek;跨零点营业(如酒吧到凌晨两点)直接写 closes: "02:00" 导致语义变成"当天凌晨两点已关门";节假日特殊时间没处理。

写法 问题 正确做法
只有 opens/closes,无 dayOfWeek 被理解为每天同一时间,周末不同的店出错 按天拆成多条 Specification
跨零点写 closes: 02:00 语义歧义 拆成两天:当天到 23:59 + 次日 00:00 到 02:00
节假日无特殊时段 AI 回答节假日营业状态错误 补充 openingHoursSpecification 的有效区间或用特殊公告

2.3 geo:坐标精度与地址不一致

geo 字段给了 latitude/longitude 后,AI 引擎通常直接信任坐标。常见错误是坐标取自商户注册地而非实际门店位置,或者复制坐标时丢精度(小数点后少于 4 位在城市尺度上偏差可达数十米)。坐标必须与 address 指向同一个门牌,建议统一从地图服务按门牌号重新取点,不要沿用商户后台的旧数据。

2.4 priceRange:写法不统一等于没写

priceRange 接受字符串,但"¥""¥100-200""人均 80 元""中等"各种写法混杂时,引擎无法归一化。规范层面向的做法是给出区间数字,如 "priceRange": "¥¥""priceRange": "80-120 CNY"。全站统一样式,比单页"漂亮"的写法更有价值。

2.5 areaServed 与服务半径

上门服务类商户常见错误是漏写服务范围,或者用一段话描述"服务全城及周边"。规范做法是 areaServed 用 City/AdministrativeArea 或 GeoCircle 明确圈出范围:

{
  "@type": "HomeAndConstructionBusiness",
  "name": "Example 家电维修(湖心路店)",
  "areaServed": [
    { "@type": "City", "name": "泉州市" },
    {
      "@type": "GeoCircle",
      "geoMidpoint": { "@type": "GeoCoordinates", "latitude": 24.9139, "longitude": 118.5894 },
      "geoRadius": "15000"
    }
  ]
}

geoRadius 单位是米,写成字符串数值即可。有没有这段,直接决定"XX 路附近能不能上门"这类问题的回答质量。

2.6 review 与 aggregateRating:自证评分的风险

评分字段是本地服务页被引用的强信号,但也是造假重灾区。两条纪律:review 的作者、日期必须真实可追溯;aggregateRating 必须来自站内真实评价体系,且 reviewCount 与页面上可见的评价数一致。用假数据填 ratingValue: "5" 的做法,在 AI 引擎交叉验证(对比地图平台评分)时很容易被识别为不可信站点,连累其他字段的引用。

2.7同品牌多门店:Organization 与分店关系

连锁品牌常见的结构错误是每个门店页各写各的,品牌层没有聚合。规范做法是品牌用 Organization,门店用 LocalBusiness 并通过 parentOrganization 关联,同时每家店用独立 URL 与独立 Schema,不要在首页堆一个巨型数组。另有一个容易被忽略的字段是 hasMap:指向地图平台门店页的规范链接(而不是搜索结果链接)能帮助引擎快速完成实体对齐,连锁店多的站点统一填这一字段,对实体消歧有明显帮助。

2.8 把服务页只标成 LocalBusiness

只有门店实体没有服务实体,AI 引擎就不知道"这家店能提供什么服务"。给每项核心服务补 Service 节点并用 provider 关联门店,serviceType 写行业通用的服务名词(如"空调维修"而非营销口号),召回率才会有质的变化。

三、校验工具链:别只靠 Rich Results Test

很多团队的校验流程只有 Google 的富媒体测试一条路,这不够。建议三层校验:

层级 工具 覆盖什么 局限
语法层 JSON-LD 解析器 / schema.org 官方定义 结构合法、类型字段存在 不管语义对错
语义层 Rich Results Test、Schema Markup Validator 字段取值格式、必需字段 以 Google 口径为准
业务层 自建规则脚本 坐标与地址一致、评分与可见评价数一致、营业时间与后台一致 需要自己维护规则

业务层是重点。写一个简单的流水线脚本,把站内所有商户页的 Schema 拉下来跑规则:

import json, requests
from datetime import datetime

RULES_CRITICAL = ['name', 'address', 'telephone', 'geo', 'openingHoursSpecification']

def fetch_ld(url: str) -> list:
    html = requests.get(url, timeout=10, headers={'User-Agent': 'schema-bot/1.0'}).text
    blocks = []
    for part in html.split('<script type="application/ld+json">')[1:]:
        try:
            blocks.append(json.loads(part.split('</script>')[0].strip()))
        except json.JSONDecodeError:
            blocks.append({'@error': 'json-decode-failed'})
    return blocks

def validate(node: dict, url: str) -> list:
    problems = []
    if node.get('@type') == 'json-decode-failed':
        return [f'{url}: JSON 解析失败']
    for field in RULES_CRITICAL:
        if field not in node:
            problems.append(f'{url}: 缺少 {field}')
    geo, addr = node.get('geo', {}), node.get('address', {})
    if geo and not addr.get('addressLocality'):
        problems.append(f'{url}: 有坐标但缺市级行政区')
    lat = geo.get('latitude')
    if lat is not None and len(str(lat).split('.')[-1]) < 4:
        problems.append(f'{url}: 坐标精度不足({lat})')
    for spec in node.get('openingHoursSpecification', []):
        if 'dayOfWeek' not in spec:
            problems.append(f'{url}: 营业时间缺 dayOfWeek')
    rating, reviews = node.get('aggregateRating', {}), node.get('review', [])
    if rating and rating.get('reviewCount', 0) < len(reviews):
        problems.append(f'{url}: aggregateRating.reviewCount 小于可见评价数')
    return problems

if __name__ == '__main__':
    urls = [line.strip() for line in open('merchant_urls.txt', encoding='utf-8') if line.strip()]
    report = []
    for u in urls:
        for node in fetch_ld(u):
            report += validate(node, u)
    print('\n'.join(report) or 'ALL PASS', flush=True)

把它挂进发布流程,商户后台每次保存资料就触发一次校验,错误字段在入库前就被拦下,比上线后靠搜索引擎报错反馈要快得多。

四、一份可直接对照的自查清单

把上面的内容收敛成一张表,改造时逐行打勾:

字段 常见错误 达标标准
address 单字符串地址 PostalAddress 五级拆分
geo 精度低、与地址不符 与门牌号一致,小数≥4 位
openingHours 缺 dayOfWeek、跨零点错误 按天拆分,特殊假日单独处理
priceRange 写法混乱 全站统一数字区间或符号档位
areaServed 缺失或纯文字 City 或 GeoCircle 明确圈定
review/aggregateRating 数据造假、口径不一 真实评价,数量与页面一致
品牌结构 门店各自孤立 parentOrganization 关联
服务实体 只有 LocalBusiness 核心服务补 Service 节点

这张清单的用法建议是"先全局、后逐页":先用批量脚本扫全站,统计八类错误的分布,优先修复覆盖率最高、影响召回最大的两类(我们遇到过的大多数站点是 address 与 openingHours 占全部错误的一半以上);然后再对重点门店页做人工逐字段核对。修复顺序按影响面排,而不是按页面重要性排,因为对 AI 引擎来说,一个字段级错误的重复出现会被泛化理解为"这个站的数据口径不可靠",影响的不只是出错的那一页。

五、误区澄清与收尾

两个常见误区需要澄清。一是认为 Schema 校验通过就万事大吉——语法正确不代表业务正确,坐标指向错误的门店一样会被引用出去,业务层校验不可省。二是认为本地服务页只要做了 Schema 就能被推荐——AI 引擎还会交叉比对地图平台、评价平台的公开数据,站内信息与第三方平台数据长期不一致的商户,可信度会被持续拉低,所以 Schema 改造要和平台资料治理同步做。

趋势上,AI 引擎对本地生活类问题的回答正在从"列清单"转向"给结论",结论依赖的正是这类逐字段的结构化事实。技术上,这件事没有太多发挥空间:把字段写对、把口径统一、把校验做成发布流程的一部分,剩下的交给时间。如果你的站点也在做 LocalBusiness 治理,欢迎在评论区交流你踩过的字段坑。


关键词:LocalBusiness Schema、JSON-LD 结构化数据、PostalAddress 地址规范、openingHoursSpecification 营业时间、aggregateRating 评分、GEO 生成式引擎优化、AI 优化 AIO、Schema 校验工具

🤖
本内容由 AI 辅助生成,经人工校对审核;部分素材、资料来源于公开网络,仅作个人观点分享与交流使用,无任何商业侵权意图。若内容、图片、文字涉及您的合法著作权、版权权益,请联系本人,核实后将第一时间删除、修改相关内容。