给 AI

翻页:cursor、分页和每一页的费用

在 okdata 里翻页:一次调用是一页、扣一次费,page.next_cursor 和 has_more 的含义,cursor 的使用规则,带页数上限的 Python 循环,cursor 过期怎么办,以及 POST 批量查询。

列表接口一次调用返回一页,每一页都单独按一次调用计费。要下一页,就把 page.next_cursor 作为 cursor 传回同一个接口,其他参数保持不变。page.has_more 为 false 就说明取完了;数据够用了也可以随时停下,你没要的页不会收费。

一次调用 = 一页 = 一次扣费

列表接口的返回里,data.items 旁边总有一个 page:

"page": { "next_cursor": "c1.k3Vq9TzR0bYw2LmXe8NdPa", "cursor_expires_at": "2026-11-13T08:00:00Z", "has_more": true, "returned": 20 }
  • next_cursor 是一个不透明的字符串。原样传回即可,不要解析它、自己拼它,也不要当成数字存。
  • cursor_expires_at 是这个 cursor 失效的时间;returned 是这一页的条数。
  • has_more 为 true 当且仅当 next_cursor 有值。false 加上 next_cursor: null(cursor_expires_at 也是 null),表示这个列表没有下一页了。

抖音视频评论一页大约 20 条,$0.002,所以翻十页就是十次调用,共 $0.02。按条计费的列表接口,费用跟着每页实际条数走:X 账号粉丝每页满 200 个账号,五个满页共 $0.10。按次和按条两种计费方式的区别,见计费说明。

这里没有页码。平台自己的信息流只知道“某个位置之后是什么”,所以想看第 5 页,就得先把第 1 到第 4 页取一遍。也有少数列表接口根本没有 cursor 参数,比如相关关键词,一次就返回全部结果;接口页的参数表里看得出来。

cursor 的规则

一个 cursor 只能接着同一个列表往下翻。这些检查都在扣钱之前完成:

  • 同一个账户。 拿到 cursor 的账户下的任何一把 Key 都能用它。
  • 同一个接口、同样的参数。 换了搜索词、id 或筛选条件,cursor 就对不上了。view 和 fields 每页都可以改,因为它们只影响返回的样子,不影响取什么数据。
  • 在有效期内。 每个可翻页接口在目录里都写着 cursor 的有效期 cursorTtlSeconds(在 /openapi.json 里是 x-cursor-ttl-seconds)。目前所有可翻页接口都是 86,400 秒,也就是 24 小时。

用不了的 cursor 会被拒绝,每种情况有自己的错误码,都是 charged: false,并带 param: "cursor":

code HTTP 含义 怎么办
cursor_invalid 400 不是我们发出的 cursor,或者是发给别的账户的 把 page.next_cursor 原样传回
cursor_mismatch 400 发到了别的接口,或者参数变了 按它所在那一页的参数重新发
cursor_expired 410 超过了有效期(page.cursor_expires_at) 不带 cursor,从头开始取
cursor_unavailable 502 只有返回上一页的数据源能接着翻,它现在不可用 稍后用同一个 cursor 重试,或者不带 cursor 从头开始

从头开始会把前面几页重新取一遍,也会重新计费;这期间平台顶部可能又多了新内容,所以请记下已经拿到的 id,跳过重复的条目。把 cursor 存起来、第二天再接着跑的任务,就会遇到 cursor_expired;一口气翻完的任务则不会。

带页数上限的循环

下面的代码逐页读取抖音评论,最多取 max_pages 个计费页;如果 cursor 过期,就从头再来:

import os
import requests

URL = "https://api.okdata.online/v1/douyin/videos/comments/list"
HEADERS = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}

def comments(video_id, max_pages=10, cursor=None):
    seen, pages = set(), 0
    while pages < max_pages:
        params = {"id": video_id, **({"cursor": cursor} if cursor else {})}
        body = requests.get(URL, headers=HEADERS, params=params, timeout=60).json()
        if body["code"] == "cursor_expired":
            cursor = None  # 被拒绝不扣费:从头开始
            continue
        if body["code"] != "ok":
            raise RuntimeError(f"{body['code']}: {body.get('problems') or body['message']}")
        pages += 1
        for item in body["data"]["items"]:
            if item["id"] not in seen:
                seen.add(item["id"])
                yield item
        if not body["page"]["has_more"]:
            return
        cursor = body["page"]["next_cursor"]

for c in comments("7301234567890123456", max_pages=3):
    print(c["id"], c["text"][:60])

三页最多花 $0.006。每一页都是一个新请求,所以如果你带了 Idempotency-Key,每页要用一个新的 key,只有重发同一页时才沿用原来那个。

has_more 提前变成 false

按条计费的列表接口,第一页如果余额付不起满页,会缩到余额够付的条数,warnings 里会写明,而且即使后面还有数据,这一页也不会给下一页的 cursor。充值后从头再取,就能拿到满页。之后的每一页都要有付得起满页的余额,不够时返回 402 insufficient_balance,不扣费。

用 POST 批量查询

少数单对象接口也能一次传一组 id:目录里它们的 post 为 true,一次最多能传几个,看 /prices.json 里的 batch_max(ids 参数的说明里也写着)。X 账号信息一次最多 100 个:

curl -s "https://api.okdata.online/v1/x/users/get" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids": ["4398626122", "11348282"]}'

批量调用的返回里,data.items 按查到的顺序排列,data.missing 列出没查到的 id,每个都带 reason。批量调用没有 page,也没有 cursor。按条计费的批量调用按查到的对象收费,最多 $0.04;按次计费的批量调用,比如抖音星图达人资料,一次最多 50 个 id,只收一次 $0.004。一个都没查到的批量调用不收费;传的 id 超过接口上限,会在预扣之前就返回 invalid_params。请求的其他规则见请求说明。

更新于

接上一次,以后直接问 AI。

新 key 自带 $0.10 试用额度。贴一句话,就能接进你的智能体。

免费开始
一句话接进你的 AI

把这句话发给你的智能体

读一下 https://okdata.online/zh/agents.md,帮我把 okdata 配好;我的 key 在环境变量 OKDATA_API_KEY 里。

Claude Code、Cursor、Codex 等能打开网址的智能体,读完会自己配好。

MCP 地址https://api.okdata.online/mcp