本地Schema与结构化数据
High Contrast
Dark Mode
Light Mode
Sepia
Forest
2 min read347 words

本地 Schema 与结构化数据

Schema 标记是你与 Google 之间的"机器可读合同"——正确实现后,地图包、星级评分、营业时间全部出现在搜索结果里。

本地结构化数据体系

graph TD SCHEMA[Schema.org] --> LOCAL[LocalBusiness] SCHEMA --> REVIEW[Review / AggregateRating] SCHEMA --> EVENT[Event] SCHEMA --> FAQ[FAQPage] SCHEMA --> BREADCRUMB[BreadcrumbList] LOCAL --> RESTAURANT[Restaurant] LOCAL --> MEDICAL[MedicalBusiness] LOCAL --> STORE[Store] LOCAL --> SERVICE[ProfessionalService] REVIEW --> SNIPPET[星级摘要 Rich Snippet] LOCAL --> MAPPACK[Map Pack 展示] FAQ --> ACCORDION[FAQ 折叠摘要] style LOCAL fill:#c8e6c9,stroke:#388e3c,stroke-width:2px style SNIPPET fill:#e3f2fd,stroke:#1565c0,stroke-width:2px

Schema 生成与验证工具

"""
本地 Schema 生成器与验证器
"""
from dataclasses import dataclass
import json
@dataclass
class LocalBusinessSchema:
"""完整的 LocalBusiness Schema 数据"""
name: str
business_type: str          # Restaurant / Store / MedicalClinic 等
description: str
url: str
phone: str
email: str
address_street: str
address_city: str
address_region: str
address_postal: str
address_country: str
latitude: float
longitude: float
hours: list[dict]           # [{days: [...], opens: "09:00", closes: "18:00"}]
rating_value: float
rating_count: int
price_range: str            # "$" / "$$" / "$$$"
image_url: str
same_as: list[str]          # 社交媒体/目录 URL(增强 E-E-A-T)
class SchemaGenerator:
"""JSON-LD Schema 生成器"""
@staticmethod
def local_business(b: LocalBusinessSchema) -> dict:
schema = {
"@context": "https://schema.org",
"@type": b.business_type,
"name": b.name,
"description": b.description,
"url": b.url,
"telephone": b.phone,
"email": b.email,
"address": {
"@type": "PostalAddress",
"streetAddress": b.address_street,
"addressLocality": b.address_city,
"addressRegion": b.address_region,
"postalCode": b.address_postal,
"addressCountry": b.address_country,
},
"geo": {
"@type": "GeoCoordinates",
"latitude": b.latitude,
"longitude": b.longitude,
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": h["days"],
"opens": h["opens"],
"closes": h["closes"],
}
for h in b.hours
],
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": str(b.rating_value),
"reviewCount": str(b.rating_count),
"bestRating": "5",
"worstRating": "1",
},
"priceRange": b.price_range,
"image": b.image_url,
"sameAs": b.same_as,
}
return schema
@staticmethod
def faq(questions: list[dict]) -> dict:
"""FAQPage Schema"""
return {
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": q["question"],
"acceptedAnswer": {
"@type": "Answer",
"text": q["answer"],
},
}
for q in questions
],
}
@staticmethod
def breadcrumb(items: list[dict]) -> dict:
"""BreadcrumbList Schema"""
return {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": i + 1,
"name": item["name"],
"item": item["url"],
}
for i, item in enumerate(items)
],
}
class SchemaValidator:
"""Schema 基础验证(无需 API)"""
REQUIRED_LOCAL_FIELDS = [
"name", "address", "telephone", "geo",
"openingHoursSpecification", "aggregateRating",
]
@classmethod
def validate(cls, schema: dict) -> dict:
errors = []
warnings = []
# 必填字段检查
for field in cls.REQUIRED_LOCAL_FIELDS:
if field not in schema:
errors.append(f"缺少必填字段: {field}")
# 评分范围检查
rating = schema.get("aggregateRating", {})
rv = float(rating.get("ratingValue", 0))
rc = int(rating.get("reviewCount", 0))
if rv < 1 or rv > 5:
errors.append(f"ratingValue {rv} 超出有效范围 1–5")
if rc < 1:
warnings.append("reviewCount 为 0,Google 可能不显示星级")
# sameAs 检查
if not schema.get("sameAs"):
warnings.append("缺少 sameAs — 添加 Google Maps/社交链接增强信任")
# 图片检查
if not schema.get("image"):
warnings.append("缺少 image — 有图片的 Schema 更易获得 Rich Results")
return {
"有效": len(errors) == 0,
"错误": errors,
"警告": warnings,
"建议提交": "Google Rich Results Test 验证后提交 Search Console",
}
# 演示
gen = SchemaGenerator()
# LocalBusiness 示例
biz = LocalBusinessSchema(
name="快修星 — 上海浦东店",
business_type="ElectronicsStore",
description="专业手机维修、电脑维修,30分钟快修,提供上门服务",
url="https://kuaixiuxing.com/locations/shanghai-pudong/",
phone="+86-21-88888001",
email="pudong@kuaixiuxing.com",
address_street="张杨路1600号",
address_city="上海",
address_region="上海",
address_postal="200122",
address_country="CN",
latitude=31.2304,
longitude=121.5434,
hours=[
{"days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], "opens": "09:00", "closes": "20:00"},
{"days": ["Saturday", "Sunday"], "opens": "10:00", "closes": "18:00"},
],
rating_value=4.7,
rating_count=245,
price_range="$$",
image_url="https://kuaixiuxing.com/images/pudong-store.jpg",
same_as=[
"https://maps.google.com/?cid=12345",
"https://weibo.com/kuaixiuxing",
"https://www.dianping.com/shop/H123456",
],
)
schema = gen.local_business(biz)
validator = SchemaValidator()
validation = validator.validate(schema)
print("=== LocalBusiness Schema 生成 ===")
print(json.dumps(schema, ensure_ascii=False, indent=2)[:600] + "\n...(截断)")
print("\n=== Schema 验证结果 ===")
print(f"  有效: {'✅' if validation['有效'] else '❌'}")
if validation["错误"]:
for e in validation["错误"]:
print(f"  ❌ 错误: {e}")
for w in validation["警告"]:
print(f"  ⚠️ 警告: {w}")
print(f"  建议: {validation['建议提交']}")
# FAQ Schema 示例
faq = gen.faq([
{"question": "快修星浦东店在哪里?", "answer": "位于上海浦东新区张杨路1600号,紧邻正大广场和陆家嘴地铁站。"},
{"question": "手机维修需要多长时间?", "answer": "常见问题如换屏、换电池通常30分钟内完成,复杂维修当天取机。"},
])
print(f"\n=== FAQ Schema 示例({len(faq['mainEntity'])} 条) ===")
print(json.dumps(faq, ensure_ascii=False, indent=2))

Schema 类型对应的 Rich Results

Schema 类型 搜索展示效果 适用页面
LocalBusiness Map Pack 展示、营业时间、电话 门店落地页
AggregateRating 黄色星级 + 评价数 产品/服务页
FAQPage 折叠问答 Rich Snippet FAQ 页、产品页
BreadcrumbList URL 路径替换为面包屑 所有层级页面
Event 活动日期和地点高亮 活动页

行动清单

下一章08-AI搜索变革/01-SGE与AEO优化 — AI 重塑搜索结果页,SEO 策略需要同步进化。