跳转到内容

错误处理

开放 API 的错误分两层,处理方式完全不同:

层级 在哪里看 含义 例子
请求级 响应体的 ret 不为 1 这次 HTTP 请求没有被受理,没有创建任务、不扣费 参数错误、余额不足、Key 无效
任务级 任务的 status 为 failed 或 canceled,原因在 error_code 任务已创建,但没有成功拿到回答,不扣费 平台抓取失败、派发前 Key 失效

请求失败时 HTTP 状态码仍是 200,响应体为:

{
"ret": 1023,
"msg": "{\"zh\":\"点数余额不足,请充值后重试\",\"en\":\"Insufficient credits. Please top up and try again.\"}"
}
  • 程序判断一律用 ret。 文案可能调整,不要按文案做逻辑。
  • msg 是一个 JSON 字符串,解析后得到 {"zh": "…", "en": "…"} 两种语言的提示,可以直接展示给你的用户。为稳妥起见,解析失败时把 msg 原文当作提示即可。
  • 参数错误 1001 的提示会写明具体字段,例如「参数错误:query 不能超过 4096 个字符」。
ret 含义 可能出现在 可以重试吗 处理建议
1 成功 全部 — —
1001 参数错误:请求体不是单个 JSON 对象、超过 64 KiB、包含未定义的字段,或字段值不合法 全部 否 按提示修正请求。注意字段名要用下划线风格,如 task_id、wait_seconds
1022 开发者 API 计费未开通 提交任务 否 联系商务开通
1023 点数余额不足 提交任务 充值后 充值,或改用单价更低的平台 / P2 档
1024 待派发或执行中的任务数已达上限 提交任务 是,稍后 等部分任务结束后再提交,见限流与配额
1025 提交过于频繁 提交任务 是,稍后 降低提交速率,退避后重试
1029 平台暂不支持或正在维护 提交任务 换平台 重新获取平台列表,换一个可用平台
1030 API Key 缺失、无效、已停用或已过期 全部 否 检查 Key,见认证与 API Key
1031 任务不存在 查询任务 否 检查 task_id;只能查询自己账号下的任务
1003 无权限(账户权限异常,例如 Key 所属账户的所有权已转移) 全部 否 少见,请联系我们
-1 服务暂时不可用 全部 是,退避 指数退避重试;提交任务时遇到要先确认是否已创建,见下文

请求级错误(-1 除外)都发生在创建任务之前:被拒绝的提交不会创建任务,也不会扣点数。

405(请求方法不是 POST)和 404(路径写错)说明请求没有进入业务处理,确定没有创建任务,修正代码后重新请求即可。

除此之外,如果收到 502、504 等非 200 状态码,或者连接超时、中断,说明请求在网络链路上出了问题,你无法确定服务端是否已经处理:

  • 查询类接口(查询平台、查询任务、任务列表):直接重试即可。
  • 提交任务:先按下文「提交结果未知时」的流程确认,再决定是否重新提交。

任务的 status 为 failed 或 canceled 时,error_code 说明原因。失败和取消的任务都不扣点数,预占的点数会退回。

error_code status 含义 处理建议
crawl_failed failed 平台没有返回有效回答(超时、平台异常等) 稍后重试,或换平台;时效要求不高时可改用 P2,平台不可用时会排队等待恢复
credential_invalid failed 任务派发前,提交它的 API Key 已停用、删除或过期 换一个有效 Key 重新提交
crawler_rejected failed 平台暂不支持或已下线 重新获取平台列表,换平台
crawler_internal_error failed 抓取服务内部错误,任务没有被受理 稍后重试
crawler_submit_failed failed 抓取服务没有受理这个任务 稍后重试
crawler_invalid_request failed 抓取服务拒绝了这次的请求参数 检查问题内容和 country 后重新提交
crawler_method_unavailable failed 抓取服务未开通原始结果抓取(服务端配置问题) 请联系我们
crawler_auth_failed failed 服务端配置问题 请联系我们
crawl_canceled canceled 任务被取消 需要的话重新提交

下面两个值出现在未结束的任务上,不代表失败:

error_code status 含义
dispatch_uncertain dispatching 正在确认派发结果,服务端会自行确认、不会重复派发,继续轮询即可
crawler_query_unavailable 未结束 暂时无法同步执行进度,继续轮询;长时间不变化请联系我们

error_message 与请求级错误的 msg 格式相同,是一个 JSON 字符串,解析后得到 {"zh": "…", "en": "…"} 两种语言的提示,可以写进日志或按语言展示给用户;解析失败时按原文处理。不要按文案做程序判断,分支请用 error_code。raw_result.error(以及 result_json 里的 error)格式相同。

情况 做法
-1、网络错误、非 200 状态码(查询类接口) 指数退避重试,例如 2、4、8 秒…,最多几次
1024、1025 不会创建任务,等待后重试是安全的;同时降低并发和提交速率
-1、超时、连接中断(提交任务) 不要直接重试,先确认是否已创建,见下节
1001、1003、1022、1023、1029、1030、1031 不要自动重试,修正问题后再请求
任务 failed / canceled 重新提交会创建新任务,成功后才扣费;crawl_failed 建议间隔一段时间或换平台

提交请求超时、连接中断或返回 -1 时,任务可能已经创建。直接重试会产生第二个任务,两个都成功就会扣两次点数。正确做法:

  1. 调用任务列表,用 keyword 传入刚才的问题文本(keyword 最多 256 个字符,按「包含」匹配,长问题取前 256 个字符即可),start_time 设为提交前的时间。
  2. 找到了:继续轮询那个 task_id。
  3. 没找到:重新提交。
# BASE_URL、HEADERS 的定义同快速开始
import json
import time
import requests
RETRYABLE = {-1, 1024, 1025}
class MaxAEOError(Exception):
def __init__(self, ret, msg):
self.ret = ret
try:
self.message = json.loads(msg).get("zh") or msg
except (TypeError, ValueError, AttributeError):
self.message = msg
super().__init__(f"ret={ret}: {self.message}")
def post(path, body):
resp = requests.post(BASE_URL + path, headers=HEADERS, json=body, timeout=30)
resp.raise_for_status()
data = resp.json()
if data["ret"] != 1:
raise MaxAEOError(data["ret"], data.get("msg", ""))
return data["data"]["ent"]
def get_with_retry(path, body, retries=4):
"""查询类接口:可以安全重试。"""
for attempt in range(retries + 1):
try:
return post(path, body)
except (requests.RequestException, MaxAEOError) as e:
retryable = not isinstance(e, MaxAEOError) or e.ret in RETRYABLE
if not retryable or attempt == retries:
raise
time.sleep(2 ** (attempt + 1))
def submit_safely(platform, query):
"""提交任务:只有确认没有创建过,才重新提交。"""
started = int(time.time()) - 60 # 留出时钟误差
for attempt in range(4):
try:
return post("/task/submit", {"platform": platform, "query": query})
except MaxAEOError as e:
if e.ret in (1024, 1025): # 没有创建任务,等一会儿再试
time.sleep(15 * (attempt + 1))
continue
if e.ret != -1:
raise
except requests.RequestException:
pass
# 结果未知:先找有没有刚才那次提交
found = get_with_retry("/task/key/list", {
"keyword": query.strip()[:256], "platform": platform, "start_time": started, "page_size": 5,
})
if found["items"]:
return get_with_retry("/task/get", {"task_id": found["items"][0]["task_id"]})
raise RuntimeError("提交多次未成功,请稍后再试")

需要我们协助排查时,请提供:

  • task_id(任务相关问题);
  • 请求时间(精确到分钟)与调用的接口;
  • 响应头里的请求追踪 ID ipalfish-trace-id(如有);
  • 完整的 ret、msg 或 error_code、error_message。

不要把完整的 API Key 发给任何人,包括我们的工作人员。