SERP API 计费口径:credits_charged、执行失败扣费与退款边界

SERP API 计费口径:credits_charged、执行失败扣费与退款边界

很多人对 SERP API 的成本核算是这么算的:"一次请求 1 credit,我跑 1000 次就是 1000 credits。"这个算法在大多数日子成立,但在你排查"为什么余额掉得比预期快"的那天会失效------因为文档写得很清楚:执行失败(executed failures)也可能被扣费 ,而 credits_charged 的官方定义是"退款逻辑应用后"的扣费数。这篇把计费口径逐条对齐,给一个能对账的脚本。字段与价格以 SerpBase 官方文档的计费说明 与官网为准。

计费的基本盘

各端点每次成功请求的 credits:

端点 credits
/google/search 1
/google/news 1
/google/video/search 1
/google/image/search 2
/google/maps/search 2
/google/maps/detail 2
GET /account/credits 0(限流 60 次/分)

信封里有个字段 credits_charged,文档对它的描述是"Credits charged after refund logic is applied"------这是你实际被扣的数字,权威来源。所以做账要以响应里的这个字段为准,不是以"这个端点标价多少"为准。

执行失败也扣费,这是最容易算错的一条

文档 Billing 一节的原话是"Per-request catalog price; executed failures may be charged"。官网价格页说得更直白:timeouts 和 unknown executions(无法判定是否执行的请求)不会自动退款。

翻译成工程语言:

  • 请求发出去了、上游执行了、返回了一个错误(比如参数错误、上游没有结果)------这类"已执行的失败"可能照扣。
  • 请求超时了、你不知道它到底执行没执行------不自动退款,按已执行处理。
  • 只有明确符合退款逻辑的情况,才会在 credits_charged 里体现为少扣或不扣。

所以批量脚本里常见的那种"失败了就当没花钱,明天重试"的思路,会让你低估成本。重试本身不是问题,问题是重试前没人把已扣的 credits 记进去。

对账脚本

python 复制代码
import json, pathlib, requests

API = "https://api.serpbase.dev"
KEY = "你的 API Key"
HEADERS = {"X-API-Key": KEY, "Content-Type": "application/json"}

def balance() -> dict:
    """GET /account/credits,0 credits,限流 60 次/分。"""
    resp = requests.get(f"{API}/account/credits", headers=HEADERS, timeout=15)
    data = resp.json()
    if data.get("status") != 0:
        raise RuntimeError(f"{data.get('status')}: {data.get('error')}")
    return data

def search(q: str, page: int = 1) -> tuple:
    resp = requests.post(f"{API}/google/search", headers=HEADERS,
                         json={"q": q, "hl": "zh-CN", "gl": "cn", "page": page},
                         timeout=30)
    data = resp.json()
    return data, data.get("credits_charged", 0)

def run(keywords: list) -> dict:
    before = balance()
    spent, failures, rows = 0, 0, []
    for kw in keywords:
        for page in (1, 2):
            data, charged = search(kw, page)
            spent += charged
            if data.get("status") != 0:
                failures += 1
                # 失败也记成本:已执行的失败可能照扣
                rows.append({"关键词": kw, "页": page, "状态": data.get("status"),
                             "扣费": charged, "request_id": data.get("request_id")})
                continue
            rows.append({"关键词": kw, "页": page, "状态": 0,
                         "扣费": charged, "request_id": data.get("request_id"),
                         "条数": len(data.get("organic", []))})

    pathlib.Path("billing_log.jsonl").write_text(
        "\n".join(json.dumps(r, ensure_ascii=False) for r in rows), encoding="utf-8")

    after = balance()
    return {
        "跑前余额": before["credits"],
        "跑后余额": after["credits"],
        "响应累加扣费": spent,
        "失败请求数": failures,
        "差额": before["credits"] - after["credits"] - spent,
        "记录条数": len(rows),
    }

if __name__ == "__main__":
    report = run(["SERP API 价格", "谷歌地图数据采集"])
    for k, v in report.items():
        print(f"{k}: {v}")

关键在最后那个 差额:跑前余额 − 跑后余额 应该等于响应里 credits_charged 的累加值。如果差额不为 0,说明有扣费发生在你记录之外 ------最常见的原因就是失败/超时请求被扣了费但你的脚本只在成功分支里记了账。这个脚本把失败分支也记 charged,就是为了让两边对得上。

三条成本纪律

  1. 预算按"请求数 × 端点单价 × 1.2"估,不按请求数 × 单价估。 那 20% 是给失败重试和超时留的余量。真要精确,就跑一轮小批量,用 差额 字段反推你的实际失败扣费率。
  2. 余额预检放在批量开头。 GET /account/credits 是 0 credits 的端点,跑之前先取一次余额,和 len(keywords) × 每词页数 × 端点单价 比一下,不够就停。比跑到一半报 1020(余额不足)强------至少那时候你手里有一份完整的部分结果,而不是一份断在中间的 CSV。
  3. expiring_credits 要单独看。 余额响应里有 credits/permanent_credits/expiring_credits/expiring_expires_at 四个字段。如果余额看着够用但大部分是限时 credits,你面对的是排期问题不是预算问题:限时的先用掉,长期任务靠 permanent 那部分。

FAQ

失败自动退款吗? 不保证。文档只说 credits_charged 是"退款逻辑应用后"的数字,并明确"executed failures may be charged";官网进一步说明超时和无法判定的执行不自动退款。所以把 credits_charged 当权威账本,别把"失败=免费"当默认。

价格是多少? 100 次免费额度起步(不绑卡);付费包 Starter 10/20k(0.50/1k)、Growth 50/125k(0.40/1k)、Pro 200/570k(0.35/1k)、Business 500/1500k(0.33/1k)、Enterprise 1000/3300k(0.30/1k)。另有 Starter Boost $3/月 10k credits,但那是限时订阅制(月内有效),标准包的 credits 不过期。具体以官网当天价格为准。

1020 是什么? 余额不足的错误码。遇到它先查 GET /account/credits,别急着重试------重试只会继续扣。

为什么 maps/image 比 search 贵? 标价就是 2 credits 对 1 credits,文档里按端点列明的。做地图网格采集时把格点数先算清楚再跑,超预算了先停。

把对账脚本接进你的定时任务,每周看一眼 差额------这个数字比任何"感觉最近掉得有点快"都可靠。

相关推荐
蒸鱼Yuzheng3 小时前
设备端性能工件可靠导出:断点续传、哈希、manifest 与失败恢复
android·自动化测试·python·adb·数据完整性
圆圆讲门店3 小时前
挑选同城获客服务机构时需要考量的核心因素都有哪些?
大数据·网络·人工智能·python
傻啦嘿哟4 小时前
Python的默认参数把我坑惨了,原来写[]和写None的区别这么大
开发语言·python·机器学习
微小冷4 小时前
Python凸优化cvxpy初步
python·机器人·凸优化·数学规划·cvxpy
在世修行4 小时前
干货:显式映射 vs 自动判据
python·插件
xzal124 小时前
Python之简单理解栈和队列
python
lupai4 小时前
维修保养记录精准版 API 对接实战指南
数据库·python
水水不水啊5 小时前
告别杂乱的调试窗口:我用 Python + WebView 写了一个现代化串口助手
python·测试工具·嵌入式·嵌入式开发·串口调试·串口助手
三水写代码5 小时前
手写一个 Claude Code(1):从 Agent Loop 到工具、权限、Hooks 与任务规划
python·ai编程·claude·ai agent·claudecode