绕口令与谜语查询:分页遍历指南(用 page/allPages 拉取全部数据)
# 绕口令与谜语查询:分页遍历指南(用 page/allPages 拉取全部数据)
**接口**:绕口令与谜语查询(apiCode=1623)· 接入点 1623-1 / 1623-2|**是否免费**:免费(含使用档次限制)|**请求方式**:POST/GET|**返回格式**:JSON|**适用人群**:需要全量语料的开发者、运营|**阅读时间**:约 6 分钟
## 核心要点
- 翻页靠 `page` 参数,从 `1` 循环到 `showapi_res_body.allPages`;`allNum` 是总数可用于校验。
- 免费接口有档次限制,**逐页循环会快速消耗额度**,务必配合本地缓存(见[本地缓存策略](https://www.showapi.com/guides/tongue-riddle-cache-tier-1623))。
- 生产级写法要带「失败重试 + 指数退避 + 单页上限控制」,不要裸循环。
## Why:什么时候需要翻页?
做离线语料库、批量生成卡片、全量备份时,单页约 10 条不够用。用分页把全部绕口令/谜语拉下来,落库后日常查询走本地,不再反复打接口。
## What:分页四字段回顾
| 字段 | 含义 |
|------|------|
| `page` | 请求参数,页码,默认 1,字符串类型 |
| `currentPage` | 当前返回的页码 |
| `allPages` | 总页数,循环终点 |
| `allNum` | 总条数,可用于校验累计条数 |
## How:自动翻页 + 重试(Python)
```python
import time
import requests
APP_KEY = "YOUR_APPKEY"
URL = "https://route.showapi.com/1623-1" # 谜语改用 1623-2,timeout 改 15
TIMEOUT = 5
def fetch_page(keyword: str, page: int, max_retry: int = 3) -> dict:
for attempt in range(max_retry):
try:
resp = requests.post(
URL,
params={"appKey": APP_KEY},
data={"title": keyword, "page": str(page)},
timeout=TIMEOUT,
)
body = resp.json()["showapi_res_body"]
if body["ret_code"] != "0":
raise RuntimeError(body.get("showapi_res_error"))
return body
except Exception as e:
if attempt == max_retry - 1:
raise
time.sleep(2 ** attempt) # 指数退避:1s, 2s
return {}
def collect_all(keyword: str = "") -> list:
results, page = [], 1
while True:
body = fetch_page(keyword, page)
results.extend(body.get("contentlist", []))
total_pages = int(body.get("allPages", "1"))
if page >= total_pages:
break
page += 1
return results
all_items = collect_all("") # 空关键词拉全部绕口令
print("累计条数:", len(all_items), "接口总条数:", fetch_page("", 1).get("allNum"))
```
**cURL(手动翻第 2 页)**
```bash
curl -X POST "https://route.showapi.com/1623-1?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
-d "title=&page=2"
```
**Node.js(fetch,带超时与重试)**
```javascript
const APP_KEY = "YOUR_APPKEY";
const URL = `https://route.showapi.com/1623-1?appKey=${APP_KEY}`;
const TIMEOUT = 5000;
async function fetchPage(keyword, page, maxRetry = 3) {
for (let attempt = 0; attempt < maxRetry; attempt++) {
try {
const body = new URLSearchParams({ title: keyword, page: String(page) });
const resp = await fetch(URL, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body,
signal: AbortSignal.timeout(TIMEOUT),
});
const data = await resp.json();
if (data.showapi_res_body.ret_code !== "0") throw new Error(data.showapi_res_error);
return data.showapi_res_body;
} catch (e) {
if (attempt === maxRetry - 1) throw e;
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
}
}
}
async function collectAll(keyword = "") {
const out = [];
let page = 1;
while (true) {
const body = await fetchPage(keyword, page);
out.push(...body.contentlist);
if (page >= Number(body.allPages)) break;
page++;
}
return out;
}
```
## 返回示例与解析
单页返回结构见[返回字段全解](https://www.showapi.com/guides/tongue-riddle-response-fields-1623);遍历时关注 `allPages` 作循环终点、`allNum` 作总数校验。
## 进阶 / 边界
- **免费档位是硬约束**:逐页循环对免费接口消耗很快,拉全量建议低频执行(如每日一次)并落库复用。
- 两接入点独立分页:绕口令的 `allPages` 与谜语的 `allPages` 互不影响,分别遍历。
- 单页上限 `maxResult=1000`,但实际返回约 10 条,不要以为一次能拿 1000 条。
## FAQ
**Q1:page 传数字还是字符串?**
A:文档示例为字符串(如 `"1"`),建议传字符串,避免个别网关类型转换问题。
**Q2:拉到一半失败了怎么办?**
A:用「已落库的最后页码」做断点续传,从失败页重新 fetch,配合上面的重试逻辑。
**Q3:免费接口翻很多页会被限流吗?**
A:会。文档明确有使用档次限制,全量遍历请控制频率并缓存结果,详见[本地缓存策略](https://www.showapi.com/guides/tongue-riddle-cache-tier-1623)。
**Q4:allPages 很大(如 100)正常吗?**
A:正常,表示内容库总量大;逐页拉取耗时与额度消耗都会随页数线性增长。
**Q5:能并发翻页加速吗?**
A:可,但免费接口档位有限,并发更易触发限制;建议串行 + 退避,或确认额度后再并发。
## 下一步阅读
- [绕口令与谜语查询:绕口令关键词检索实战](https://www.showapi.com/guides/tongue-riddle-twister-query-1623)
- [绕口令与谜语查询:谜语关键词检索实战](https://www.showapi.com/guides/tongue-riddle-riddle-query-1623)
- [绕口令与谜语查询:免费档位下的调用纪律与本地缓存策略](https://www.showapi.com/guides/tongue-riddle-cache-tier-1623)
- **本系列共 12 篇**:查看[绕口令与谜语查询指南总目录](https://www.showapi.com/guides/tongue-riddle-guides-1623)