API 限流机制:8 次 / 30 秒、200 次 / 天,怎么优雅处理
SauceNAO 免费账户的 API 限流不是单一数字——它是一个双层漏斗:30 秒窗口内限 8 次、24 小时窗口内限 200 次。理解这个机制能帮你写出不会被限流卡住的健壮代码。
双层限流的含义
| 窗口 | 免费额度 | 说明 |
|---|---|---|
| 短窗口(30 秒) | 8 次 | 防止短时间内爆刷服务器 |
| 长窗口(24 小时) | 200 次 | 防止长期滥用 |
两个窗口独立计算——短窗口耗尽后等 30 秒恢复,长窗口耗尽后等 24 小时(自然日或滚动 24 小时,SauceNAO 没明确说,实测是滚动)。
API 响应里的额度信息
每次 API 调用的 JSON header 里都会返回剩余额度:
{
"header": {
"short_remaining": 7,
"long_remaining": 198
}
}
你每次调用后都应该读这两个值——它们是最可靠的限流状态来源。
第三方库的自动处理
pysaucenao 和 saucenao-api 都内置了限流保护:
- 每次请求后检查
short_remaining。 - 如果
short_remaining == 0,自动等待 30 秒再发下一次。 - 如果
long_remaining == 0,直接抛异常让你知道。
所以用第三方库的话,短窗口限流几乎不用你管——库帮你等。但长窗口耗尽还是要自己处理。
自己写脚本时怎么处理
如果你不用第三方库、直接调 HTTP 请求:
import time
import requests
API_KEY = "your_key"
SHORT_WAIT = 30 # 短窗口耗尽后的等待时间
def search_image(image_url):
resp = requests.get(
"https://saucenao.com/search.php",
params={
"output_type": 2,
"api_key": API_KEY,
"url": image_url,
"db": 999,
},
)
data = resp.json()
header = data["header"]
# 检查长窗口
if header["long_remaining"] == 0:
print("24 小时额度耗尽,等明天再来")
return None
# 检查短窗口
if header["short_remaining"] == 0:
print(f"短窗口耗尽,等 {SHORT_WAIT} 秒")
time.sleep(SHORT_WAIT)
return data["results"]
批量搜索的策略
如果你有一堆图片要搜:
- 串行搜:一张一张来,每张之间留 2~3 秒间隔。SauceNAO 搜索引擎本身就要 3~5 秒,间隔自然产生了。
- 不要并行:同时开 8 个线程搜很容易撞短窗口限流。即使你控制好了并发,SauceNAO 服务器也扛不住高并发请求。
- 每天搜 200 张封顶:免费账户的 24 小时额度就是 200,超出了也搜不了。多准备几个账户轮流用或升级。
升级账户后的变化
升级账户后短窗口和长窗口额度都会提升(具体数字以账户升级页面为准)。但限流机制本身不变——还是双层漏斗,只是数字更大。升级账户适合每天要处理上千张图的场景(比如做一个公共服务机器人)。
网页端为什么不限流?
网页端没有 API 那种硬限制——但如果你短时间内疯狂刷新搜索、连续搜几十张图,SauceNAO 可能会临时封禁你的 IP 几分钟。网页端的限流是软性的、IP 级别的,不像 API 那样精确到账户和请求次数。
建议
日常个人使用(每天几十次)→ 免费账户完全够,用第三方库自动处理短窗口限流。批量处理(每天几百次)→ 免费账户能覆盖大部分,实在不够就升级。服务化(每天上千次)→ 必须升级 + 做好错误重试和退避。