Python
Client Python officiel pour la plateforme Crawlbase. Un seul package englobe toutes les API - Crawling, Scraper, Smart AI Proxy, Storage, Crawler, Screenshots - avec une ergonomie Python idiomatique pour les paramètres, les erreurs et les retries.
Architecture du SDK
Le SDK Python est un wrapper léger, avec peu de dépendances, autour de la même API HTTP documentée dans la référence de l'API. Chaque paramètre de la Crawling API que vous ajouteriez en query string dans un appel HTTP brut est accessible depuis le SDK comme un mot-clé dans le dict d'options : noms, valeurs par défaut et comportements correspondent un à un. Le SDK n'ajoute aucun paramètre ; le SDK n'en masque aucun.
Ce que vous gagnez à l'utiliser plutôt que requests directement :
- Encodage des URL, validation des paramètres et parsing des réponses gérés d'emblée : votre code applicatif se lit comme du code produit, pas comme de la plomberie HTTP.
- Une classe client unique par API Crawlbase, partageant toutes le même constructeur et la même forme d'appel ; une fois que vous en avez utilisé une, vous les avez toutes utilisées.
- Des valeurs par défaut sensées (timeout de 90 secondes, parsing JSON des réponses
format=json, décodage UTF-8 automatique) qui correspondent à ce que la plupart des équipes configurent à la main lors de leur première intégration. - Une surface d'apprentissage réduite : cinq classes clientes, deux verbes (
get/post), une seule forme de réponse.
Le SDK est open source, sous licence MIT, et accepte les PRs de la communauté sur github.com/crawlbase/crawlbase-python. La plupart des problèmes signalés sont corrigés dans une release en moins d'un sprint.
Installation
Dernière version sur PyPI. Nécessite Python 3.7+ ; testé jusqu'à Python 3.13.
pip install crawlbase
# Or via Poetry / uv / pip-tools
poetry add crawlbase
uv add crawlbaseSources sur GitHub. Issues et PRs bienvenues.
Authentification
Toutes les API Crawlbase s'authentifient avec le même modèle de token : il n'y a pas de clé API distincte par produit. Deux types de tokens cohabitent sur un même compte :
- Normal Token (TCP) - pour le HTML statique, les endpoints JSON, tout ce qui ne nécessite pas de navigateur. Plus rapide et moins coûteux.
- JavaScript Token
- pour les SPA, les flux chargés en lazy-loading et toute cible qui dissimule son contenu derrière un rendu côté client. Requis pour utiliser
page_wait,ajax_wait,scrolletcss_click_selector.
Utilisez des variables d'environnement en production plutôt que de coder en dur vos tokens. Le SDK ne lit pas lui-même les variables d'environnement : c'est un choix délibéré pour que vous gardiez le contrôle de la provenance de vos identifiants, mais le pattern idiomatique est le suivant :
import os
from crawlbase import CrawlingAPI
# Pick the right token at instantiation; the SDK doesn't switch
# tokens per-call, so keep two clients if you alternate.
api = CrawlingAPI({'token': os.environ['CRAWLBASE_TOKEN']})
js = CrawlingAPI({'token': os.environ['CRAWLBASE_JS_TOKEN']})
res = api.get('https://github.com/anthropic')
res = js.get('https://feed.example.com', {'page_wait': 2000})Modèle de token complet et emplacements dans le dashboard sur la page Authentication.
Démarrage rapide
Trois lignes entre l'import et le HTML crawlé :
from crawlbase import CrawlingAPI
api = CrawlingAPI({'token': 'YOUR_TOKEN'})
res = api.get('https://github.com/anthropic')
if res['status_code'] == 200:
print(res['body'])Branchez sur status_code (le statut HTTP de la requête du SDK vers Crawlbase) et pc_status (le verdict Crawlbase : voir Erreurs ci-dessous) au moment de décider s'il faut réessayer. Le body est en bytes par défaut ; passez 'format': 'json' pour recevoir une enveloppe JSON plutôt que le contenu brut de la page.
Toutes les APIs dans un seul package
Chaque API Crawlbase a sa classe cliente correspondante. Même constructeur, mêmes verbes get / post. Choisissez la classe selon ce que vous faites ; en coulisses, chacune appelle un endpoint différent de la même plateforme.
from crawlbase import (
CrawlingAPI, # general-purpose page fetch (HTML / JSON / etc.)
ScraperAPI, # parsed JSON for supported sites (Amazon, Google, etc.)
LeadsAPI, # domain-scoped email extraction (legacy)
ScreenshotsAPI, # screenshots of any URL
StorageAPI, # Cloud Storage CRUD
)
token = {'token': 'YOUR_TOKEN'}
crawl = CrawlingAPI(token)
scraper = ScraperAPI(token)
leads = LeadsAPI(token)
shots = ScreenshotsAPI(token)
storage = StorageAPI(token)
# Push high-volume async jobs to the Enterprise Crawler via the
# Crawling API: api.get(url, {'async': True, 'callback': '...',
# 'crawler': 'YourCrawler'}). See /docs/crawler for the queue
# workflow.Patterns courants
Rendu JavaScript
Pour les SPAs, les flux en lazy-load et les pages dont le HTML initial est vide, instanciez avec le JavaScript token et passez n'importe quelle combinaison de page_wait, ajax_wait, scroll et css_click_selector. Ordre à garder en tête : un délai fixe, puis l'attente de network-idle, puis le scroll pour le lazy-load, puis le clic pour tout élément d'UI bloquant.
api = CrawlingAPI({'token': 'YOUR_JS_TOKEN'})
res = api.get('https://spa.example.com', {
'page_wait': 2000,
'ajax_wait': True,
'scroll': True,
})Utiliser un scraper intégré
Évitez complètement le parser sur les sites supportés. Passez 'scraper': 'NAME' et le body de la réponse devient une chaîne JSON contenant les champs structurés documentés sur la page de chaque scraper.
import json
from crawlbase import ScraperAPI
api = ScraperAPI({'token': 'YOUR_TOKEN'})
res = api.get(
'https://www.amazon.com/dp/1098145356',
{'scraper': 'amazon-product-details'}
)
data = json.loads(res['body'])
print(data['name'], data['price'])Routage géographique
Passez 'country'='ISO' pour acheminer le crawl via les nœuds de sortie du pays correspondant. Utilisez-le dès que la cible sert un contenu localisé en fonction de l'IP : la plupart des marchands, toutes les SERP, les pages de streaming géo-restreintes.
api = CrawlingAPI({'token': 'YOUR_TOKEN'})
# Hit the German Amazon catalog from a German residential IP
res = api.get(
'https://www.amazon.com/dp/1098145356',
{'country': 'DE'}
)Asynchrone avec retries
La forme de retry recommandée : backoff exponentiel plafonné à 3-5 tentatives, retry uniquement sur erreurs transitoires (5xx ou body vide), pas de retry sur 4xx (la forme de la requête est mauvaise et ne se corrigera pas toute seule).
import time, random
from crawlbase import CrawlingAPI
api = CrawlingAPI({'token': 'YOUR_TOKEN'})
def crawl(url, attempts=5):
for i in range(attempts):
res = api.get(url)
# 200 from Crawlbase + non-empty body from the target
if res['status_code'] == 200 and int(res.get('pc_status', 0)) == 200:
return res
# Don't bother retrying client errors (4xx)
if 400 <= res['status_code'] < 500:
raise ValueError(f"client error {res['status_code']}: {url}")
# Exponential backoff with jitter
time.sleep(random.uniform(0, 2 ** i))
raise RuntimeError(f'Failed: {url}')Crawls async + webhooks
Mode fire-and-forget. L'appel SDK retourne immédiatement avec un rid ; Crawlbase POST le résultat sur votre URL de callback dès que la page est prête. Utile pour les batchs et les cibles lentes, lorsque vous ne voulez pas qu'une requête synchrone occupe un slot de concurrence pendant 30 secondes ou plus.
api = CrawlingAPI({'token': 'YOUR_TOKEN'})
res = api.get('https://example.com', {
'async': True,
'callback': 'https://your-app.com/webhook',
})
rid = res['rid'] # use this to correlate the eventual webhook delivery
# Webhook handler (Flask / FastAPI / etc.) receives a POST with:
# { rid, url, original_status, pc_status, body }Pour de très gros volumes (millions d'URLs), utilisez l'Enterprise Crawler qui se place devant ce même pipeline asynchrone avec retries, gestion du rate et livraison des résultats.
Sessions persistantes
Certains flux nécessitent la même IP résidentielle sur plusieurs appels : un checkout, une recherche paginée, une session authentifiée. Passez 'cookies_session' avec un identifiant stable et Crawlbase réutilise le même nœud de sortie pendant environ 30 minutes.
api = CrawlingAPI({'token': 'YOUR_JS_TOKEN'})
session = f'checkout-{user_id}'
api.get('https://shop.example.com/cart', {'cookies_session': session})
api.get('https://shop.example.com/checkout', {'cookies_session': session})
api.get('https://shop.example.com/confirm', {'cookies_session': session})Erreurs & retries
La plateforme Crawlbase expose deux codes de statut sur chaque réponse : le status_code propre au SDK (le statut HTTP de la requête vers Crawlbase elle-même) et pc_status (le verdict de Crawlbase sur la cible : voir le tableau des erreurs de la Crawling API pour la liste complète). Branchez toujours sur pc_status au moment de décider s'il faut réessayer : une cible peut renvoyer 200 avec un body vide, auquel cas status_code vaut 200 mais pc_status vaut 520.
res = api.get(url)
pc = int(res.get('pc_status', 0))
if pc == 200:
use(res['body'])
elif pc in (520, 525):
# 520 = empty body, 525 = anti-bot couldn't be solved.
# Switch to JS token and retry.
retry_with_js_token(url)
elif pc in (521, 522, 523):
# Target unreachable or timed out. Retry with backoff.
schedule_retry(url)
else:
log.error('crawl failed', extra={'url': url, 'pc_status': pc})Tous les retries contre la plateforme sont gratuits : seules les réponses réussies (pc_status: 200) sont décomptées de votre quota. Cela rend un backoff agressif peu coûteux ; le seul vrai coût d'un retry est la latence supplémentaire.
Performance & bonnes pratiques
- Réutilisez un seul client par token. Le constructeur est peu coûteux, mais chaque instance ouvre son propre pool de connexions. Construisez-le une fois au niveau du module et partagez-le entre les appels.
- Utilisez le token le moins cher qui fonctionne. Ne basculez pas par défaut sur le JavaScript token « au cas où » : les requêtes avec le Normal token sont plus rapides et consomment moins de concurrence. Passez au JS uniquement quand la réponse Normal est vide ou bloquée par l'anti-bot.
- Préférez
ajax_waitàpage_wait. Les délais fixes consomment de la concurrence sur chaque requête, même les rapides.ajax_waitretourne dès que la page atteint l'état network-idle. - Pour les batchs : async + webhook, ou push vers l'Enterprise Crawler. Le mode synchrone est le bon défaut pour de l'ad-hoc et de l'interactif ; pour une soumission soutenue à fort volume, passez en async afin que votre slot de concurrence se libère dès qu'une requête est mise en file plutôt qu'à sa complétion.
- Surveillez l'en-tête de réponse
remaining. Il indique le nombre de slots de concurrence qu'il vous reste : un client sain réduit son débit de manière proactive avant d'atteindre le plafond plutôt que de réagir aux 429.
Référence des méthodes
Toutes les classes client partagent la même surface. Le constructeur prend un seul dict d'options ; les verbes reflètent les méthodes HTTP sous-jacentes.
'timeout' en secondes (par défaut 90) - s'applique à l'appel HTTP du SDK vers Crawlbase, pas au crawl en amont.options est un dict associant n'importe quel paramètre de la Crawling API à sa valeur. Retourne un dict de réponse.data est le body : passez un dict pour un encodage form, une string pour du brut. options fonctionne comme pour .get.Forme de la réponse (dict, toutes les clés présentes même quand leur valeur est vide) :
200 signifie que la requête a été acceptée ; consultez pc_status pour le résultat sur la cible.format=json / scraper= a été utilisé).async=true ou store=true).