登录

三类错误

每一个 Crawlbase 错误都会归入三个类别之一,每一类都需要不同的应对方式。

瞬时性
重试
网络抖动、上游短暂中断、限流。429500503522599务必使用退避策略重试。
站点侧
处理
目标站点返回了真实错误:404410451。不要重试 - 该页面确实不存在或无法访问。将该 URL 标记为失败并继续处理下一个。
配置
修复代码
您这边的问题。401402403422。重试无济于事 - 请修正请求、token 或账号。

生产环境重试模式

在高负载下经得住考验的模式:带完全抖动的指数退避、限定尝试次数,并为最终失败设置死信目标。

import time, random, logging
from crawlbase import CrawlingAPI

api = CrawlingAPI({'token': 'YOUR_TOKEN'})
log = logging.getLogger('crawler')

TRANSIENT = {429, 500, 503, 522, 599}
TERMINAL  = {401, 402, 403, 404, 410, 422, 451}

def crawl(url, max_attempts=5, base=0.5, cap=30):
    for attempt in range(max_attempts):
        res = api.get(url)
        status = res['status_code']

        if status == 200 and res['pc_status'] == 200:
            return res

        if status in TERMINAL or res['pc_status'] in TERMINAL:
            log.warning(f'Terminal error {status}/{res['pc_status']} for {url}')
            raise PermanentFailure(url, status)

        # Transient - sleep with full jitter, then retry
        wait = min(cap, base * (2 ** attempt))
        wait = random.uniform(0, wait)
        log.info(f'Attempt {attempt+1} got {status}; sleeping {wait:.2f}s')
        time.sleep(wait)

    raise RuntimeError(f'Exhausted retries for {url}')

class PermanentFailure(Exception): pass
const { CrawlingAPI } = require('crawlbase');
const api = new CrawlingAPI({ token: process.env.CRAWLBASE_TOKEN });

const TRANSIENT = new Set([429, 500, 503, 522, 599]);
const TERMINAL  = new Set([401, 402, 403, 404, 410, 422, 451]);

async function crawl(url, { maxAttempts = 5, base = 500, cap = 30000 } = {}) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const res = await api.get(url);
    const status = res.statusCode;

    if (status === 200 && res.pcStatus === 200) return res;

    if (TERMINAL.has(status) || TERMINAL.has(res.pcStatus)) {
      throw new Error(`Permanent failure \${status} for \${url}`);
    }

    const wait = Math.random() * Math.min(cap, base * 2 ** attempt);
    await new Promise(r => setTimeout(r, wait));
  }
  throw new Error(`Exhausted retries for \${url}`);
}

死信队列

重试用尽后,不要悄无声息地丢弃 URL。将其推送到人工可审查的位置。

  • Crawler API 用户:失败会自动按您配置的次数进行重试,然后连同失败元数据一起投递到您的 webhook。无需自建 DLQ。
  • 直接调用 API 的用户:当最终失败时,将 URL + 状态 + 最后一次响应 body 写入单独的队列或表中。每周复查一次。
不要无限重试

将重试次数限制在 5 次左右。一个连续失败 5 次的 URL,几乎肯定也会失败 50 次。把资源留给新任务。

应监控什么

每个使用 Crawlbase 的系统都应监控的四个指标:

指标来源告警条件
成功率pc_status == 200 / 总数< 95% 持续 10 分钟
P95 延迟请求耗时> 15s 持续
429 比率HTTP 状态码直方图> 5% 持续出现 - 调高并发
重试次数分布您的重试循环P95 > 2 - 上游出现劣化

为每项指标打上目标域名标签,这样当某个单一站点拖累整体数据时,您能立刻发现。

让重试变得安全

Crawlbase 请求本质上是幂等的 - 使用相同的 token 对同一 URL 发起 GET 每次都会返回相同类型的结果。您可以放心重试,无需担心重复的副作用。

两点说明:

  • Async + store:如果使用了 &async=true&store=true,每次重试都会消耗一个额度并生成一个新的 rid。如有需要,请在您这一侧做去重。
  • Webhooks:Crawler API webhook 在失败时可能被多次投递。请让您的 webhook 处理器基于 rid 实现幂等。