百度搜索 API:用 Python 跑通第一次实时检索
# 百度搜索 API:用 Python 跑通第一次实时检索
> 接口:百度搜索(apiCode=3351,接入点 3351-1)· 官方自营 · 按次计费
> 请求方式:POST / GET · 返回格式:JSON · 适用人群:第一次接入的开发者
> 阅读时间:约 6 分钟 · **最后实测核对:2026-09-15**
你给大模型接一个"查最新消息"的能力,最省事的做法不是自己爬网页,而是套一层搜索接口。百度搜索 API(apiCode=3351)就是干这个的:扔进去一个 `query`,拿回来一组网页结果,每条都带标题、正文片段、发布时间和站点信息。
这篇只做一件事——让你在十分钟内跑通第一次调用,并看懂返回的那坨 JSON。
## 核心要点
- 必填参数只有一个 `query`,其余四个全部可选。
- 接口地址 `https://route.showapi.com/3351-1?appKey={your_appKey}`,POST 和 GET 都能用。
- 拿到响应后真正要处理的是 `showapi_res_body.references` 数组,`showapi_res_code` 先用来看这次请求有没有被受理。
## 先做什么
你需要一个 AppKey。登录 showapi 后在我的账号 → 控制台里能找到,接口页右上角「查看我的 appKey」也是同一个。
AppKey 怎么给?放在 URL 的 query 参数里:`?appKey=xxxx`。不是放 Header。
## 接口速览
| 项 | 值 |
|----|----|
| 接口地址 | `https://route.showapi.com/3351-1` |
| 鉴权 | URL 参数 `appKey` |
| 请求方式 | POST(`application/x-www-form-urlencoded`)/ GET |
| 接入点 | 1 个,编号 3351-1 |
| 必填参数 | `query`(≤72 字符,一个汉字算 2 个字符) |
| 可选参数 | `count`、`search_domain_filter`、`block_domain_filter`、`search_recency_filter` |
| 返回格式 | JSON |
| 计费 | 按次,规格资源包自购买起 12 个月有效 |
| 单次耗时(实测) | 0.36s ~ 1.42s(7 次有耗时记录的调用) |
## 第一步:发一次最小请求
先跑最简版本,只传 `query`。
**Python**
```python
import requests
url = "https://route.showapi.com/3351-1"
params = {"appKey": "YOUR_APPKEY"} # AppKey 走 URL 参数
data = {"query": "昆明天气"} # query 是唯一的必填项
resp = requests.post(url, params=params, data=data, timeout=10)
resp.raise_for_status()
result = resp.json()
if result.get("showapi_res_code") != 0:
raise RuntimeError(f"调用失败:{result.get('showapi_res_error')}")
body = result.get("showapi_res_body") or {}
print("ret_code =", body.get("ret_code"), "命中", len(body.get("references") or []), "条")
for item in (body.get("references") or [])[:3]:
print(item["id"], item["title"], item["url"])
```
用 `requests` 传中文 `query` 是安全的,它会自己按 UTF-8 编码。后面第 3 节讲为什么强调这一点。
**cURL**
```bash
curl -X POST "https://route.showapi.com/3351-1?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
--data-urlencode "query=昆明天气"
```
注意用 `--data-urlencode`,不要写 `-d "query=昆明天气"`,也别在 Windows 命令行里直接内联中文(第 3 节解释了原因)。中文参数最好从文件读:`--data-binary @params.txt`,文件存为 UTF-8。
**Node.js**
```javascript
const url = new URL("https://route.showapi.com/3351-1");
url.searchParams.set("appKey", "YOUR_APPKEY");
const resp = await fetch(url, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ query: "昆明天气" }).toString(),
signal: AbortSignal.timeout(10000),
});
const result = await resp.json();
if (result.showapi_res_code !== 0) {
throw new Error(`调用失败:${result.showapi_res_error}`);
}
const list = result.showapi_res_body.references || [];
console.log(`命中 ${list.length} 条`);
list.slice(0, 3).forEach(it => console.log(it.id, it.title, it.url));
```
`URLSearchParams` 会按 UTF-8 编码,中文没问题。
## 第二步:看懂返回
下面是 2026-09-15 用 `query=昆明天气`、`count=10` 实际调用拿到的结果(`content` 字段太长,已截断):
```json
{
"showapi_res_error": "",
"showapi_res_id": "6aa89f36fb638c2f69c7113d",
"showapi_res_code": 0,
"showapi_fee_num": 1,
"showapi_res_body": {
"remark": "",
"ret_code": 0,
"references": [
{
"id": 1,
"type": "web",
"title": "国庆云南旅游天气怎么样?专属穿衣搭配+出行防护指南,适配全域各地游玩场景!",
"url": "https://www.163.com/dy/article/...",
"website": "网易",
"date": "2026-09-15 09:25:08",
"snippet": "国庆假期临近,云南各地天气…",
"content": "国庆假期临近,云南各地天气…(最多 2000 字片段,此处截断)",
"authority_score": 0.5,
"rerank_score": 1,
"icon": "https://.../favicon.ico",
"web_anchor": "",
"markdown_content": "",
"web_extensions": {
"images": [
{ "url": "https://.../xxx.jpeg", "height": "405", "width": "550" }
],
"author_info": {}
}
}
]
}
}
```
两层结构要分清:
- 外层是系统级字段。`showapi_res_code = 0` 表示这次请求在网关层就被受理了。
- 内层 `showapi_res_body` 是业务数据。`ret_code = 0` 表示这次检索成功,`references` 才是结果数组。
`showapi_fee_num = 1` 是本次扣费次数。这个字段值得单独留意——**请求失败时它是 0**,也就是不扣费。细节在[计费与缓存那篇](https://www.showapi.com/guides/baidu-search-api-billing-cache-3351)里。
字段含义一个个讲清楚的是[返回字段那篇](https://www.showapi.com/guides/baidu-search-api-response-fields-3351),这里你先记住三件事:`title` 是标题,`url` 是原文地址,`content` 是可以直接喂给大模型的正文片段。
## 第三步:把参数用起来
`count` 控制返回条数。文档写的可填范围是 10、20、30、40、50,默认 10。
实测结论:**填范围外的数字不会报错,会被静默忽略、回落成默认 10 条。** 2026-09-15 用 `count=3` 测试,返回了 10 条;`count=10` 返回 10 条,`count=20` 返回 20 条。所以别指望用 `count=5` 省流量,它不是"要几条给几条"。
另外三个参数控制结果的来源和时间范围:
```python
data = {
"query": "大模型",
"count": "20",
"search_recency_filter": "week", # 只要最近 7 天
"search_domain_filter": "baike.baidu.com", # 只要这个域名的结果
# "block_domain_filter": "baijiahao.baidu.com", # 或者反过来:屏蔽某个域名
}
```
`search_recency_filter` 只能填四个枚举值:`week`(7 天)、`month`(30 天)、`semiyear`(180 天)、`year`(365 天)。传别的值不会生效,也没有"自定义起止日期"这个能力。
## 进阶与边界
**中文参数的编码坑。** 这是实测踩到的:在 Windows 的 Git Bash / cmd 里用 `-d "query=昆明天气"` 内联中文,参数可能被按 GBK 送出去,接口收到的是一串乱码。当时用查询词"昆明天气"调用,返回的前几条是酷狗音乐页面和金山词霸的单词页——和查询意图完全没有关系。换用 `--data-urlencode` 或把参数写进 UTF-8 文件后恢复正常。
判断自己有没有踩这个坑很简单:看返回的 `url` 字段里还有没有正常的中文,如果出现 `w=??????` 这类内容,就是编码问题,不是接口的问题。
**`query` 长度上限 72 个字符。** 一个汉字算两个字符,也就是 36 个汉字。文档说超长会"只取前 72 个字符检索",这点实测可以验证:用 59 个汉字(118 字符)的长句调用,和把它截到前 36 个汉字(72 字符)再调用,两次返回的 10 条 `url` 完全一致。所以长查询别指望接口帮你总结,先自己把关键词提出来。
**没有的能力。** 这个接口不返回结果总数,也没有翻页参数,一次最多 50 条。想要更多结果得换关键词多次调用。
## FAQ
**Q1:`showapi_res_code` 和 `ret_code` 都是 0 才是成功吗?**
两个层级都要看。`showapi_res_code = 0` 表示网关受理了请求,`showapi_res_body.ret_code = 0` 表示检索成功。如果 `showapi_res_code` 不是 0,`showapi_res_body` 会是空对象或直接不存在,直接取 `references` 会报错。
**Q2:为什么我传了 `count=50` 却只收到十几条?**
`count` 是上限不是保证。实测中加了 `search_domain_filter` 或 `block_domain_filter` 之后,符合条件的网页不够,返回条数会少于 `count`,接口不会用其他网页补齐。
**Q3:AppKey 能放在请求头里吗?**
这个接口的鉴权参数是 URL 上的 `appKey`。放 Header 不是它约定的方式。
**Q4:GET 能用吗?**
能。2026-09-15 实测 GET 方式(参数拼在 URL 上)返回 `showapi_res_code=0`、`ret_code=0`,结果与 POST 一致。中文参数记得做好 URL 编码。
**Q5:单次调用大概要多久?**
实测记录到耗时的 7 次调用在 0.36s 到 1.42s 之间,并发和加过滤条件的请求偏慢。超时时间建议设 10 秒以上。
## 下一步阅读
- [百度搜索 API 返回字段:references 里 13 个字段逐个说清](https://www.showapi.com/guides/baidu-search-api-response-fields-3351) —— 把返回结构吃透
- [百度搜索 API 报错怎么查](https://www.showapi.com/guides/baidu-search-api-error-codes-3351) —— 装一份错误对照表,出问题不用猜
- [在 RAG 里接入百度搜索 API](https://www.showapi.com/guides/baidu-search-api-rag-agent-3351) —— 如果你的目标就是给大模型联网
---
- **本系列共 8 篇**:查看[百度搜索 API 指南总目录](https://www.showapi.com/guides/baidu-search-guides-3351)