错误处理
大规模爬取意味着错误难免发生。提前为此做好准备,您就能把时间花在交付功能上,而不是盯着重试。
三类错误
每一个 Crawlbase 错误都会归入三个类别之一,每一类都需要不同的应对方式。
429、500、503、522、599。务必使用退避策略重试。404、410、451。不要重试 - 该页面确实不存在或无法访问。将该 URL 标记为失败并继续处理下一个。401、402、403、422。重试无济于事 - 请修正请求、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): passconst { 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实现幂等。