SERP API JSON Schema 演进版本管理实战

SERP API 返回 JSON 会演进,新字段加、旧字段改,下游解析会崩。做好版本管理,升级不炸。

1. 为什么需要 Schema 管理

SERP API 返回 JSON 的结构,不同版本有差异:

  • v1: organic[].title / snippet
  • v2: 加 people_also_ask[](延伸问题)
  • v3: 加 ai_overview(AI 摘要)
  • v4: organic[].snippet 改名为 organic[].description(破坏性)

下游解析器跟着版本走,不管理就会崩。

2. JSON Schema 定义

先定义 API 返回的 schema:

json 复制代码
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://serpbase.dev/schema/v1/search.json",
  "type": "object",
  "properties": {
    "status": { "type": "integer" },
    "request_id": { "type": "string" },
    "organic": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["title", "link"],
        "properties": {
          "title": { "type": "string" },
          "link": { "type": "string" },
          "snippet": { "type": "string" },
          "position": { "type": "integer" }
        }
      }
    },
    "people_also_ask": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "question": { "type": "string" },
          "answer": { "type": "string" }
        }
      }
    }
  },
  "required": ["status", "organic"]
}

3. Schema 版本管理

git 管理 + semver 版本号:

bash 复制代码
schemas/
├── v1.0.0-search.json
├── v1.1.0-search.json   # 加 people_also_ask
├── v2.0.0-search.json   # 破坏性:snippet → description
└── v3.0.0-search.json   # 加 ai_overview
  • minor(1.1.0):加字段,不破坏
  • major(2.0.0):改字段名,破坏

4. 校验库

Python 用 jsonschema:

python 复制代码
import jsonschema
from jsonschema import validate, Draft202012Validator

def validate_serp(data, schema_path='schemas/v1.1.0-search.json'):
    """校验 SERP 数据是否符合 schema"""
    schema = json.load(open(schema_path))

    try:
        validate(instance=data, schema=schema)
        return True, None
    except jsonschema.ValidationError as e:
        return False, str(e)

# 测试
data, error = validate_serp(serp_response)
if not data:
    print(f"Schema violation: {error}")

5. 自动适配不同版本

下游解析器适配多个版本:

python 复制代码
def parse_serp(data):
    """自适应解析 SERP 数据,兼容多版本"""

    # 检测版本
    version = detect_version(data)

    if version >= '2.0.0':
        # 新版:description 替代 snippet
        snippet_field = 'description'
    else:
        # 旧版:snippet
        snippet_field = 'snippet'

    results = []
    for item in data.get('organic', []):
        results.append({
            'title': item['title'],
            'snippet': item.get(snippet_field, ''),  # 兼容
            'link': item['link'],
            'position': item.get('position', 0)
        })

    # ai_overview(v3+)
    if 'ai_overview' in data:
        results.append({
            'type': 'ai_overview',
            'text': data['ai_overview'].get('text', '')
        })

    return results

def detect_version(data):
    """检测数据版本"""
    if 'ai_overview' in data:
        return '3.0.0'
    if 'people_also_ask' in data:
        return '1.1.0'
    return '1.0.0'

6. 兼容策略

3 种兼容策略:

python 复制代码
class SchemaCompat:
    """Schema 兼容处理"""

    def __init__(self):
        self.versions = {
            '1.0.0': self.parse_v1,
            '1.1.0': self.parse_v1_1,
            '2.0.0': self.parse_v2,
            '3.0.0': self.parse_v3
        }

    def parse(self, data):
        version = detect_version(data)
        return self.versions[version](data)

    def parse_v1(self, data):
        return [{'title': i['title'], 'snippet': i['snippet']} for i in data['organic']]

    def parse_v1_1(self, data):
        items = self.parse_v1(data)
        # 加 PAA
        items.extend([
            {'type': 'paa', 'q': p['question'], 'a': p['answer']}
            for p in data.get('people_also_ask', [])
        ])
        return items

    def parse_v2(self, data):
        items = []
        for i in data['organic']:
            items.append({
                'title': i['title'],
                'description': i['description'],  # 新版字段
                'link': i['link']
            })
        return items

    def parse_v3(self, data):
        items = self.parse_v2(data)
        if 'ai_overview' in data:
            items.append({'type': 'ai_overview', 'text': data['ai_overview']['text']})
        return items

7. 下游影响分析

每次 Schema 升级,评估下游影响:

python 复制代码
def analyze_schema_change(old_schema, new_schema):
    """分析 schema 变化的破坏性"""
    breaking = []
    additive = []

    # 递归对比
    def walk(old, new, path=''):
        if isinstance(old, dict) and isinstance(new, dict):
            # 删除字段 = 破坏
            for k in old:
                if k not in new:
                    breaking.append(f'{path}.{k} removed')
            # 新增字段 = additive
            for k in new:
                if k not in old:
                    additive.append(f'{path}.{k} added')
            # 递归
            for k in old:
                if k in new:
                    walk(old[k], new[k], f'{path}.{k}')
        elif isinstance(old, dict) and isinstance(new, dict):
            # 类型变化 = 破坏
            if old.get('type') != new.get('type'):
                breaking.append(f'{path} type changed')

    walk(old_schema, new_schema)
    return breaking, additive

8. 版本兼容测试

自动化测试保证兼容:

python 复制代码
import pytest

# 所有历史版本的测试数据
HISTORICAL = {
    '1.0.0': {...},  # 只有 organic
    '1.1.0': {...},  # + paa
    '2.0.0': {...},  # snippet → description
    '3.0.0': {...}   # + ai_overview
}

@pytest.mark.parametrize('version,data', HISTORICAL.items())
def test_parse_compat(version, data):
    """所有历史版本都能解析"""
    parser = SchemaCompat()
    result = parser.parse(data)
    assert result is not None
    assert isinstance(result, list)

9. 实战:30 天数据

跑 30 天 Schema 管理:

指标 数值
Schema 版本 3 次(1.1 → 2.0 → 3.0)
破坏性变更 1 次(snippet → description)
下游解析失败 0
回滚次数 0
平均迁移时间 30 分钟

10. 最佳实践

几点经验:

  1. API 侧加版本参数 :?v=3.0.0
  2. 保持 snippet 兼容:加 description 的同时保留 snippet(过渡期)
  3. schema 文档化:每个字段标注引入版本
  4. 提前通知:破坏性变更至少提前 30 天
  5. 灰度:先灰度 1% 流量验证

11. API 版本参数

serpbase 支持版本参数:

python 复制代码
r = requests.post(
    'https://api.serpbase.dev/google/search?v=3.0.0',
    headers={'X-API-Key': key},
    json={'q': query}
)

12. 总结

JSON Schema 版本管理 5 件事:

  1. 定义 schema(v1.0.0)
  2. git + semver 管理
  3. 校验(jsonschema)
  4. 兼容解析(多版本适配)
  5. 破坏性评估 + 灰度

代码 GitHub 公开,clone 跑起来。

参考文档

本文 API 示例参考 serpbase 文档,接口路径、参数和返回字段以官方文档为准。

相关推荐
k4m7v2pz1 天前
16GB Mac 本地跑大模型:ollama 局域网 OpenAI 兼容 API 实战(一:需求与配置)
llm·openai·api·mac·ollama·本地·atomcode
VIP_CQCRE2 天前
用 Ace Data Cloud 快速接入 Suno 声音克隆 API:让 AI 音乐唱出你的专属声线
ai·aigc·api·音乐生成·suno
赵庆明老师2 天前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
逻极2 天前
FastAPI 实战:从入门到自动化文档,如何把API开发效率提升200%
python·api·fastapi·swagger·异步
脉动数据行情3 天前
脉动行情数据 API 新手对接实战指南
api·股票api·国际期货·国内期货
VIP_CQCRE3 天前
用 Ace Data Cloud 快速接入 Luma 视频生成 API:让 AI 视频能力进入你的产品
api·ai视频·luma·acedatacloud
VIP_CQCRE3 天前
用 Ace Data Cloud 快速接入 Suno 声音克隆 API:让 AI 音乐拥有专属声线
人工智能·ai·aigc·api·音乐生成
星核0penstarry3 天前
从 Dialog-RSN-1 看语音 Agent 走向:企业如何评估音频原生模型与 API 服务
人工智能·音视频·音频·api
gsls2008083 天前
大模型供应商API端点兼容协议
大模型·api·协议·兼容