SERP 返回 JSON 用 Pydantic 强校验:类型安全解析

SERP 接口返回的 JSON,直接当 dict 用,容易踩类型坑------rank 可能是字符串,snippet 可能缺。用 Pydantic 定义模型,强校验 + 类型安全,解析就稳了。

下面以 SerpBase 的 /google/search 接口为例。

为什么用 Pydantic

手写 data["organic"][0]["rank"] 的问题:

  • 字段缺了,KeyError
  • 类型不对,rank 是字符串,排序就乱
  • 没有 IDE 提示,全靠记

Pydantic 定义模型后,字段必填、类型校验、自动转换,还有 IDE 提示。

定义模型

python 复制代码
from pydantic import BaseModel
from typing import List, Optional

class OrganicItem(BaseModel):
    rank: int
    position: Optional[int] = None  # 别名,兼容不同字段
    title: str
    link: str
    url: Optional[str] = None
    snippet: Optional[str] = None
    date: Optional[str] = None

class SearchResponse(BaseModel):
    status: int
    request_id: str
    search_type: str = "search"
    elapsed_ms: Optional[int] = None
    credits_charged: Optional[int] = None
    organic: List[OrganicItem] = []

解析

python 复制代码
import requests

def search_typed(query):
    r = requests.post(
        "https://api.serpbase.dev/google/search",
        headers={"X-API-Key": "你的key"},
        json={"q": query, "hl": "zh-CN", "gl": "cn"},
        timeout=10,
    )
    # 直接交给 Pydantic 校验
    return SearchResponse.model_validate(r.json())

字段自动类型转换 + 校验。rank 传成字符串,会自动转 int;缺必填字段,直接报错。

别名处理

serpbase 的 organic 同时返回 rank/position、link/url。Pydantic 用 Field(alias=...) 或直接用双字段兼容:

python 复制代码
from pydantic import Field

class OrganicItem(BaseModel):
    rank: int = Field(validation_alias="rank")
    position: Optional[int] = None
    link: str
    url: Optional[str] = None

    def effective_rank(self):
        """rank 优先,position 兜底"""
        return self.rank if self.rank is not None else self.position

    def effective_link(self):
        return self.link or self.url or ""

字段校验 + 清洗

Pydantic 还能做字段级校验和清洗:

python 复制代码
from pydantic import field_validator

class OrganicItem(BaseModel):
    title: str
    snippet: Optional[str] = None

    @field_validator("snippet")
    @classmethod
    def truncate(cls, v):
        if v and len(v) > 200:
            return v[:200] + "..."
        return v

    @field_validator("title")
    @classmethod
    def strip(cls, v):
        return v.strip() if v else ""

错误处理

校验失败会抛 ValidationError,可以统一处理:

python 复制代码
from pydantic import ValidationError

def safe_search_typed(query):
    try:
        data = search_typed(query)
        return data
    except ValidationError as e:
        # 记录 + 走 fallback
        log_error(f"解析失败: {e}")
        return None

喂 LLM 前裁剪

Pydantic 模型还可以直接产出喂 LLM 的精简结构:

python 复制代码
def to_llm_context(resp: SearchResponse, limit=5) -> str:
    lines = []
    for i, item in enumerate(resp.organic[:limit], 1):
        lines.append(f"[{i}] {item.title}\n{item.snippet or ''}")
    return "\n".join(lines)

注意

  • rank 可能是 Optional :没排进结果时字段可能没有,用 Optional[int]
  • 校验失败别崩 :捕获 ValidationError,记录 + fallback
  • 版本兼容:接口字段演进,模型加字段要向后兼容

完整参数和响应字段参考:serpbase.dev/docs。Pydantic 强校验,解析 SERP 数据不再手抖。

相关推荐
譕痕4 天前
JSONObject与JSONArray封装数据格式区别
java·json
A黄俊辉A4 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
伞伞悦读4 天前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json
Mikko74 天前
jackson-databind 升到 2.21.6 就安全了吗?jackson-core 是另一个坐标,它那条 high 全局库至今没收
java·后端·安全·json
天若有情6736 天前
独立开发复盘:我用 Node.js 做了个在线工具箱
前端·json·工具
Asurplus7 天前
【SpringBoot4】3、从SpringBoot4升级Sa-Token1.46.0报错
redis·sa-token·json·jackson·springboot4
代码中介商7 天前
C++ 预约系统实战(三):服务端实现——libevent 事件驱动与业务路由
c++·json·c/s
譕痕8 天前
notepad++安装插件 可视化展示 json串内容
json·intellij-idea
databook8 天前
DuckDB + SQL 高效分析 JSON 数据
数据分析·json·nosql
数据狐(Datafox)9 天前
1688商品列表API接口解析(附 JSON 样例)
java·开发语言·数据库·爬虫·json