EveryInfra

Build in Public · LF-01

统一数据 API 入门:从能力目录到第一条可用结果

用 platform、action、params 接入多平台数据:读懂能力目录,完成最小请求,处理异步任务、部分结果与计费,并建立可追溯的数据记录。

接一个平台时,写一段请求代码通常不难。真正麻烦的是第二个平台接进来以后:参数名称变了,用户与内容的标识不同,有的接口立即返回数据,有的先创建任务。等到程序开始定时运行,失败重试、结果去重和账单核对又各自长出一套逻辑。

统一数据 API 解决的是这些重复的接入工作。在 EveryInfra 的 EveryData 中,你用同一套 Bearer 鉴权,通过 platform 选择平台、action 选择能力、params 传入该能力的参数。统一的是调用入口与通用处理方式,不是把所有平台的数据变成同一种业务对象。

这篇教程以小红书笔记搜索演示最小请求,再说明如何扩展到其他能力。目标不是“发出一次 HTTP 请求”,而是让程序知道自己取到了什么、哪些结果还没确定,以及下一次运行该如何衔接。示例依据 2026-09-04 核对的公开目录和实现;业务 POST 是供你在获准场景下改写的调用模板,不是本轮新增的成功实测。

先分清:你需要取数,还是搜索与生成

如果你已经知道对象属于哪个平台,例如某篇笔记、某个商品或某个地点,想读取它的结构化字段,数据 API 是合适的起点。若你还在问“网上哪里有这些资料”,应先做网页搜索;若你已经拿到材料,要摘要、分类或撰写报告,则属于模型处理。

以评论分析为例,采集负责回答“这些评论是什么、从哪里来”,模型负责回答“这些文本里出现了哪些问题”。后者不能补造采集失败的记录,也不能把没返回的评论数量解释为零。把这两个阶段分开,你才能在结论有争议时回到原始证据,而不必重新猜测整条调用链。

第一步:用目录确认能力,不凭平台名猜接口

能力目录可以在没有 API Key 时读取。先用 compact 版本了解可选的平台与 action,再针对选中的平台读取完整契约。compact 用于发现,会省略部分参数与字段说明;不要拿精简目录当作完整的请求校验器。

查看能力入口,不把数量写死在客户端
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?compact=1' \
  | jq '.capabilities[] | {platform, action, required_params, mode, available}'

例如,你需要找到一组与研究关键词有关的小红书笔记,应该先看 search;已经持有某篇笔记的链接,想读详情或评论,则应选择对应的 note 或 comments。名字相近不意味着可以互换:搜索的 keyword 不能直接当成详情请求的 url。

只查看小红书 search 的完整声明
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?platform=xiaohongshu' \
  | jq -e '.capabilities[] | select(.action == "search") | {
      platform, action, required_params, optional_params,
      param_meanings, mode, returns_list,
      default_limit, max_limit, response_fields, available
    }'

本次目录核对中,xiaohongshu.search 的必填参数是 keyword,mode 为 sync,returns_list 为 true;默认条数为 20,上限为 50。后两项描述本能力的数量设置,不是“每次一定交付这么多条”,更不是跨平台通用上限。目录还列出 sort 和 content_type;需要筛选时,按 param_meanings 中的允许值填写,别从另一个平台复制枚举。

  • required_params:必须提供什么输入。先满足它,再逐个添加筛选条件。
  • param_meanings:参数含义与已声明的允许值。没有枚举的字段,不自行发明枚举。
  • mode 与 returns_list:分别决定是否需要任务查询、最终业务数据是列表还是单对象。
  • response_fields:用于规划字段映射,不是一条真实响应,也不保证每个字段都有非空值。
  • available:目录层的可用标记;它不能预先证明某个目标链接此刻一定能返回数据。

列表能力还支持通用 limit;它不一定重复出现在 optional_params 中。这个区别已由请求校验代码核对。接入时同时看列表声明、默认/上限和完整说明,不要只对 optional_params 做字符串匹配,就把合法的 limit 删掉。

第二步:发送一个足够小、便于检查的请求

准备好具有相应能力权限的 API Key,在服务端环境变量中提供它。不要放到浏览器前端代码、截图或可公开下载的示例文件里。下面假设 EVERYINFRA_API_KEY 已通过你自己的密钥管理方式配置;命令只提交一次请求,没有自动重试。

小红书笔记搜索:最小业务请求
: "${EVERYINFRA_API_KEY:?请先配置服务端 API Key}"
curl --silent --show-error --include --max-time 180 \
  'https://api.everyinfra.com/api/v1/social' \
  -H "Authorization: Bearer ${EVERYINFRA_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data '{
    "platform": "xiaohongshu",
    "action": "search",
    "params": {
      "keyword": "AI tools",
      "limit": 5
    }
  }'

这里的 5 是你希望检查的小样本规模,不是交付保证;180 秒是此示例的客户端等待上限,不是服务 SLA。先用少量结果确认字段、时间格式和来源链接,再扩大数据量。初次调试保留 HTTP 状态行与响应正文,遇到 4xx 或 5xx 时才能读到具体错误,而不是只看到一条 curl 失败提示。

三个顶层字段应保持清楚:platform 与 action 负责选择能力,业务条件全部放进 params。不要把 keyword 提到顶层,也不要给所有 action 都附上 page、cursor 或 sort。目录没有开放的参数,不能靠“多数 API 都这么设计”推断它也支持。

OpenAPI 可以帮助人和程序描述请求体、参数和响应;它并不要求每个平台使用相同的业务模型。需要生成类型或开发调用器时,可以以规范理解接口描述格式,再以服务自己的目录与响应契约确定具体字段。

第三步:读懂同步结果的外层与内层

对本篇选定的 xiaohongshu.search,实现将列表放在 results,另有 id、platform、action、count、billing 和 quota 等外层信息。id 是这次请求的追踪标识;results 内每条记录的 id 才是内容标识。两者不应混用:前者用于排错和对账,后者用于记录去重。

也不要把 results 写成整个客户端唯一的取值路径。其他 action 可以返回不同名称的业务对象;returns_list 说明对象形态,字段词典解释对象内部字段,但它们都不能替代对所选能力外层结构的确认。新增一种能力时,给它一份明确的结果适配配置,比在所有响应里递归寻找第一个数组更可靠。

读取搜索结果字段的含义
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/fields?platform=xiaohongshu&action=search' \
  | jq '{fields, undocumented}'

字段处理里有两个容易影响结论的细节。第一,互动量为 null 表示未公开或不可得,不能自动补成 0 再参与平均数。第二,posted_at 的公共说明允许平台原始时间字符串被保留;不要默认所有值都能直接按同一种 ISO 格式解析。可以另存解析后的时间,并给解析失败留状态,而不是把失败日期填成今天。

如果响应带 partial 或 missed,需要把未交付的目标单独记下来;HTTP 200 不保证本批每个目标都有数据。对于空数组,最多能得出“本次没有返回记录”,不能单靠它认定原平台上不存在数据。请求是否覆盖了正确对象、是否受范围限制,是另一个问题。

第四步:异步能力要等终态,不能停在 job_id

换到 mode 为 async 的能力后,提交响应可能是 HTTP 202,并带 status、job_id 与 poll_url。先把这些字段持久化,再开始查询任务。HTTP 规范里的 202 表示请求已受理但处理尚未完成,不能拿它触发“报告已生成”之类的业务通知。

查询已经提交的任务;不要为轮询重新发送 POST
: "${EVERYINFRA_API_KEY:?请先配置提交该任务时使用的 API Key}"
: "${EVERYINFRA_JOB_ID:?请填入实际提交响应中的 job_id}"
curl --silent --show-error --include --max-time 30 \
  "https://api.everyinfra.com/api/v1/jobs/${EVERYINFRA_JOB_ID}" \
  -H "Authorization: Bearer ${EVERYINFRA_API_KEY}"

当前查询实现按提交时的 Key 归属查找 job。请使用同一把 Key 查询,不要假设同账号下换一把 Key 就能取回任务;查不到时也不要立刻再建一个相同任务。可以先核对 API 域名、job_id 和使用的 Key,必要时凭已保存的请求信息排查。

  • running 或 finalizing:仍是处理中状态。保留任务,按有限间隔继续查询。
  • succeeded:任务进入成功终态;再解析该能力的数据对象,核对是否满足你的业务需要。
  • failed:进入失败终态,读取 error 并保留任务记录,不把它当成空数据成功。
  • 查询超时或出现未知状态:只标记“本次未确认”。设置总等待预算,交给后续恢复流程,不擅自改成成功或失败。

轮询器应有最大等待时间,间隔可以逐步拉长,避免紧密循环。程序重启后,从保存的 job_id 恢复查询,而不是重新提交任务。还要单独保存提交时的 billing:当前结果查询响应并不重复提供完整计费块,不能因为查询结果里没出现 billing 就推断这次没有收费。

Microsoft 的异步请求—响应模式也把受理、状态查询和最终结果分开,并讨论轮询提示。它适合作为客户端流程的设计参考;其中的 Location、Retry-After 等头不是本文对 EveryInfra 的返回保证,实际查询仍使用本次响应给出的入口。

第五步:按错误原因处理,尤其别盲目重试 POST

业务错误需要同时读 HTTP 状态与 error.code。当前数据入口先检查鉴权,再处理能力、权限和参数,随后才进入额度与执行流程。没有有效 Key 时看到 401,不能据此判断你的业务参数已经通过校验。

  • 401:核对 Key 是否存在、有效,以及 Bearer 头是否正确。不要靠修改关键词解决鉴权失败。
  • 403:核对这把 Key 是否获准访问目标产品与能力。权限问题应由有权限的人处理,不自动切换其他账号。
  • 400 unknown_capability:检查 platform 与 action 是否匹配;重新读取目录,并审阅服务提供的候选名称。
  • 422:检查必填项、未知参数和非法枚举。优先按错误提示改一处,再发起新请求。
  • 402:额度不足,需要处理账号的额度问题;反复发送同一请求不会改变它。
  • 429、临时服务错误或网络中断:先减速并判定原请求状态。只有确认适合重试时,才做有次数上限的重试。

最容易遗漏的是“客户端超时,但服务端可能已经受理”。数据获取在业务上看似只读,实际仍通过 POST 发起,可能创建任务并发生计费。同一个业务 ID 方便你关联多次尝试,却不会自动变成服务端幂等保证。不要在没有明确接口支持时自行加一个 Idempotency-Key,然后假定重复请求只执行一次。

RFC 9110 对非幂等请求的自动重试有专门限制。对这类未知结果,应先查询已有任务或核对请求记录;拿不到足够信息时保留 unknown,比自动重放整个批次更稳妥。

第六步:把数据、采集状态和账单分开存

统一入口最有价值的部分,是让通用记录与平台字段映射分工明确。建议至少保留三类记录:一次业务任务、一次 API 尝试、一个平台对象。这样既能追踪一个任务经历过几次尝试,也能让同一条内容在多次采集中更新,而不会被算成多个新对象。

  • 任务记录:你自己的 task_id、目标范围、预期字段与完成条件。这里的“完成”由业务定义,不只是 HTTP 成功。
  • 请求记录:platform、action、参数的非敏感摘要、开始/结束时间、API 请求 id、job_id、状态与 billing。失败尝试也要留存。
  • 对象记录:platform、对象类型、对象 id、来源链接、实际取得的字段与 observed_at;不要把不同平台碰巧相同的 id 合并。

这些是你的应用数据模型建议,不是 EveryInfra 会额外返回的字段。observed_at 应由采集程序记录,表示你何时观察到结果;posted_at 表示原内容发布时间。用这两个时间分别回答“内容什么时候发布”与“我们什么时候知道它”,才能分析迟到数据和重复观察。

跨平台比较时,只映射业务确实需要且含义可比的字段。点赞、收藏、商品评分和评论条数属于不同指标;统一改名为 score 并不会让它们具备同一量纲。对于尚未解释的字段,保留缺失状态或回到字段词典,不猜测其单位和意义。

计费也不能用结果条数倒推。多目标能力会按目标计量,不能把一次 HTTP 请求当成一个计费单位;小样本 limit 不一定意味着按返回条数打折。当前同步实现会处理空结果与部分目标未交付的退款分支,但你的客户端仍应保存实际 billing 与账单记录,以便核对;不要仅凭“200”或“数组为空”自行宣布账已结清。

记录请求时可参考 OWASP 的交互标识设计:让一次业务意图下的事件可以关联,同时排除访问令牌等敏感内容。保留可排查的信息,不等于把请求头和原文全部复制进日志。

扩展到第二个平台时,哪些代码值得复用

可以复用鉴权注入、超时设置、错误记录、任务查询调度与安全日志。需要按能力保留的部分,则是参数名称和语义、结果对象路径、字段映射、分页规则与完成条件。两部分分开,后续增加能力才不会变成复制一整套客户端。

目录适合带观察时间缓存,在接入新能力或发布新版本前重新核对。不要无限使用旧缓存,也不必每取一条记录就下载全目录;根据业务对变更的容忍度设置刷新周期,遇到 unknown_capability 或参数契约冲突时再触发定向复核。

分页与增量要尤其谨慎。只有具体 action 明确提供分页参数和结束信号时,才能按它推进;没有 cursor 就不能在客户端凭空生成 cursor。定时重复查询得到的是多次观察,不自动等同于完整历史或所有新增内容。首个版本宁可明确“已检查哪些目标、哪个时间窗口”,也不要把无法证明的全量覆盖写进报告。

哪些任务不适合直接套用这套方案

如果你要代表用户发帖、管理商家资料、处理账号授权或修改平台数据,应先核对该平台对应的官方 API 与授权流程,不能把公开数据读取入口当作账号管理接口。对于私密内容、受限数据或未经许可的用途,统一接口不会扩大你的访问权。

即使数据公开可见,保存、分析、再展示仍需按具体平台规则与业务用途评估。将研究范围限制在必要目标和字段,控制保留时间,避免把作者资料、带访问参数的链接或原始文本直接输出到公开日志。技术上能够请求,与业务上允许这样使用,是两项不同检查。

从一条可解释的结果开始

完成第一轮接入时,可以问自己四个问题:我能说清楚调用的具体能力吗?我能把每条数据追溯到来源吗?我能区分成功、处理中、部分交付和未知结果吗?如果请求失败或重复,我能解释这次记录与账单吗?

这四个问题都有答案,再扩平台、加并发、接模型分析。统一数据 API 的价值不是让所有差异消失,而是让你只在真正存在平台差异的地方写专门逻辑。先从下面的文档选择一个能力,检查小样本,把结果保存正确,再开始下一步。