欢迎光临
我们一直在努力

SerpBase返回字段怎么读:一次请求拆出 11 个模块

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

SerpBase 返回字段怎么读:一次请求拆出 11 个模块

上周三下午四点,我在给一个做本地生活的小团队做交付验收。对方工程师打开 Postman,把 q 填成 best coffee in austin、gl 填成 us、device 填成 mobile,点 Send,回来 200,然后他盯着屏幕问我第一句话是:「这么多字段,我到底该取哪个?」
这不是他一个人的问题。搜索类 API 的第一次对接,卡点很少在鉴权,几乎全在响应结构:Google 结果页本身就不是线性列表,而是十几个互相独立的模块拼起来的版面,能不能把结构读对,决定了后面三个月的代码要不要返工。我那天就用这一次真实响应,把他需要的字段全部标了一遍。这篇文章是那次的复盘。

先跑通一次,再谈字段接口约定很简单:Base URL 是 https://api.serpbase.dev,鉴权走请求头 X-API-Key,请求体是 POST JSON。验证用 curl 最快:

-H 'Content-Type: application/json' \\
-H 'X-API-Key: YOUR_API_KEY' \\ –max-time 60 \\
-d '{"device":"mobile","gl":"us","hl":"en","q":"coffee shops"}'
```Python 里我用 httpx,习惯把超时显式写出来,避免默认值在弱网下制造假失败:```python
import httpxresp = httpx.post( "https://api.serpbase.dev/google/search",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"q": "coffee shops", "gl": "us", "hl": "en", "device": "mobile"},
timeout=60,)payload = resp.json()
print(payload["status"], payload["credits_charged"], payload["request_id"])
```返回里外层永远是这几个信封字段:`status`、`credits_charged`、`request_id`、`product_id`、`query`,然后才是各模块。`status` 为 0 表示成功,其他值会带错误信息。这一步跑通之后,才值得往下研究模块。
## 信封层三个字段的语义,别猜`request_id` 这个字段我建议所有团队都落库。它是唯一能把「我这边的一条日志」和「服务端的一次执行」对上号的键,出问题提工单时报这一串,找人速度完全不一样。
`product_id` 是端点标识,比如网页搜索是 `google_web_search`。做多端点混跑的项目,把它一起存下来,后面按端点统计成功率、按端点算成本,都不用再回头改表结构。
`credits_charged` 是这次请求实际扣了多少。按官方计费说明,一次 Google 搜索是 1 个 credit——不管这页返回了多少条结果、几个模块,都是 1。这里有个容易踩的细节:这个字段是三态的,`1` 是正常扣费,`0` 表示没有计费,`null` 表示还在结算中。我见过有人写 `if data["credits_charged"] > 0` 直接判断,`null` 会让比较抛异常;正确写法是先判空再比较。这一点在 [SerpBase 的计费说明](https://serpbase.dev/pricing) 里写得很清楚:请求跑了但失败(站点报错、返回空页、被拦截)会自动退款,而根本没跑起来的请求(没额度、超限流、密钥或参数非法)不扣费;超时或连接中断的,事后结算——失败退、成功扣。所以 `null` 不是异常值,是「还没定」。
顺便说失败重试:重试本身是安全的,只有成功的那一次会计费。这条让我敢在管道里直接开指数退避,不用先做一遍幂等去重。
## 十一个模块,逐块说清楚取什么官网把结果页拆成了十来块,每块一个独立字段。我按「谁最先会被用到」的顺序排:
| 字段 | 内容 | 实际用途 || — | — | — || `organic` | position、rank、title、link、snippet、date、sitelinks | 排名监控的主表 |
| `ai_overview` | text、sources、truncated | 看 AI 摘要引用了谁 |
| `people_also_ask` | question、answer、link | 扩词、做问答内容 |
| `local_results` | title、rating、reviews_count、address、hours、category | 本地商家盘点 |
| `knowledge_graph` | title、type、description、attributes、description_source | 品牌实体识别 |
| `featured_snippet` | 答案文本、来源标题与链接 | 精选摘要占位监测 |
| `top_stories` | title、source、date、link | 新闻时效性追踪 |
| `shopping_results` | title、price、merchant、rating | 电商比价 |
| `inline_videos` / `inline_images` | title、link、source、duration | 素材与视频可见性 |
| `discussions_and_forums` | title、forum、comments、date | 社区讨论占位 |
| `social_posts` | platform、author、text、date | 社媒声量 |
还有 `related_searches` 和 `people_also_search_for`,是两个纯字符串数组,做长尾扩词时比 PAA 更省事,直接拿去当下一轮 `q` 跑就行。
### organic 里 position 和 rank 不是同一件事
这是那天花时间最多的一个点。看官方示例:某条结果的 `position` 是 3,`rank` 是 1。`position` 是它在整个页面结果序列里的位置,`rank` 是在当前有机结果集合里的次序——中间那些模块会占位。做排名报表用 `rank`,做「用户第几眼看到我」用 `position`,两个混用会让曲线突然跳一段又跳回来。
另外 `link` 和 `url` 有时不同。示例里有 `link` 指向真实站点、而 `sitelinks` 里的链接是 `www.google.com/goto?url=…` 这种跳转形态,旁边还配一个 `source_url` 放原始地址。真要做域名聚合,得用 `display_link` 或 `display_url`,别拿跳转链去正则切域名。
### ai_overview 的 truncated 要当开关用
`ai_overview` 返回 `text`、`sources` 数组和 `truncated` 布尔。`truncated` 为 `true` 意味着这段摘要被截断了,别把 `text` 当完整答案喂给下游模型,否则生成的结论会缺一半前提。我在验收时特意挑了医疗、金融类词各跑一次,`truncated` 出现频率明显更高,这类词建议直接把 `sources` 交给人工看。
### local_results 的数字是字符串
`rating` 是 `"4.9"`,`reviews_count` 是 `"455"`——带引号的字符串。想排序得先 `float()`,想比较大小得先 `int()`。同理还有 `hours`,它给的是 `"Open"` 这类状态文本,不是结构化时段表,做「现在开不开门」要自己按本地时区判断,不能指望字段直接给答案。
## 一次请求的正确用法:按需取,别全取
很多团队第一版都会把整个 JSON 原样落库。跑了两周发现存储涨得比预期快得多,因为 `ai_overview` 的 `text` 和 `sources` 才是体积大头。我的做法是分两张表:主表只存 `query`、`gl`、`hl`、`device`、`request_id`、`credits_charged`、`organic` 的精简版本;`ai_overview`、`inline_images` 这些大字段单独进一张按需查询的表,需要分析时再用 `request_id` 关联。改造只花了半天,后续查询反而更快。
如果你刚开始接,建议先用官网的 Playground 跑一条,肉眼确认目标词到底会返回哪些模块,再定字段清单——不同行业差异很大,本地生活类目里 `local_results` 几乎是必取,纯工具类词则常常连 `knowledge_graph` 都没有。
## 结尾这句是真话我建议你现在就做一件事:把 `credits_charged` 的三态(`1` / `0` / `null`)写进你团队的采集规范文档,和 `request_id` 一起作为强约束。字段可以后面一个个加,但计费口径写错了,月底对账时要一条条翻日志重算,那个工作量比接十个模块都大。

赞(0)
未经允许不得转载:171主机测评 » SerpBase返回字段怎么读:一次请求拆出 11 个模块
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址