Se connecter

Trois classes d'erreurs

Chaque erreur Crawlbase appartient à l'une de ces trois catégories, et chacune appelle une réponse différente.

Transitoire
réessayer
Coupure réseau, panne brève en amont, limitation de débit. 429, 500, 503, 522, 599. Toujours réessayer avec backoff.
Côté site
gérer
Le site cible a renvoyé une véritable erreur : 404, 410, 451. Ne réessayez pas - la page n'existe vraiment pas ou n'est pas accessible. Marquez l'URL comme échouée et passez à la suite.
Configuration
corriger le code
Votre faute. 401, 402, 403, 422. Réessayer ne servira à rien - corrigez la requête, le token ou le compte.

Modèle de tentatives en production

Le modèle qui tient la charge : backoff exponentiel avec jitter complet, plafonnement des tentatives et destination de lettres mortes pour les échecs terminaux.

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}`);
}

File de lettres mortes

Quand les tentatives sont épuisées, ne jetez pas l'URL en silence. Envoyez-la quelque part où un humain peut la consulter.

  • Pour les utilisateurs du Crawler API : les échecs sont automatiquement réessayés jusqu'au nombre que vous avez configuré, puis livrés à votre webhook avec les métadonnées de l'échec. Aucune DLQ à construire.
  • Pour les utilisateurs en API directe : en cas d'échec terminal, écrivez l'URL + le statut + le dernier corps de réponse dans une file ou une table séparée. Examinez chaque semaine.
Ne réessayez pas indéfiniment

Plafonnez les tentatives à environ 5. Une URL qui échoue 5 fois de suite échouera presque certainement 50 fois. Gardez les cycles pour le nouveau travail.

Quoi surveiller

Les quatre signaux que tout système utilisant Crawlbase devrait tracer :

SignalD'où il provientAlerter quand
Taux de succèspc_status == 200 / total< 95 % pendant 10 min
Latence P95durée de la requête> 15 s en continu
Taux de 429histogramme des statuts HTTP> 5 % de façon soutenue - réduisez la concurrence
Distribution du nombre de tentativesvotre boucle de tentativesP95 > 2 - quelque chose se dégrade en amont

Étiquetez chaque métrique avec le domaine cible pour repérer quand un seul site empoisonne vos chiffres globaux.

Rendre les tentatives sûres

Les requêtes Crawlbase sont intrinsèquement idempotentes : un GET sur la même URL avec le même token renvoie le même type de résultat à chaque fois. Vous pouvez réessayer librement sans vous soucier d'effets secondaires en double.

Deux remarques :

  • Async + store : si vous avez utilisé &async=true&store=true, chaque tentative consomme un crédit et crée un nouveau rid. Dédupliquez de votre côté si nécessaire.
  • Webhooks : les webhooks du Crawler API peuvent être livrés plus d'une fois en cas d'échec. Rendez votre gestionnaire de webhook idempotent sur rid.