PHP
Client PHP officiel pour la plateforme Crawlbase. Compatible PSR, installable via Composer, fonctionne avec PHP 7.4+ - même package, toutes les APIs, valeurs par défaut sensées.
Architecture du SDK
Le SDK PHP est une fine couche au-dessus de la même API HTTP documentée dans la Référence 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 une clé du tableau d'options : noms, valeurs par défaut et comportement correspondent un pour un. Le SDK n'ajoute aucun paramètre ; il n'en cache aucun.
Ce que vous gagnez à l'utiliser plutôt que cURL ou Guzzle directement :
- Encodage des URL, validation des paramètres et parsing des réponses gérés d'office.
- Autoloading PSR-4 - s'intègre dans n'importe quel framework PHP moderne (Laravel, Symfony, Slim) sans cérémonie.
- Une classe client unique par API Crawlbase, toutes partageant le même constructeur et la même forme d'appel.
- Valeurs par défaut sensées (timeout de 90 secondes, parsing JSON automatique des réponses
format=json, corps encodés en UTF-8).
Code source sur github.com/crawlbase/crawlbase-php. Issues et PRs bienvenues.
Installation
Dernière version sur Packagist. Nécessite PHP 7.4+ ; testé jusqu'à PHP 8.3.
composer require crawlbase/crawlbase
# Or add to composer.json directly:
# "crawlbase/crawlbase": "^1.0"Authentification
Toutes les APIs Crawlbase s'authentifient avec le même modèle de token. 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 SPAs, les flux à chargement différé, tout ce qui cache du contenu derrière un rendu côté client. Requis pour utiliser
page_wait,ajax_wait,scrolletcss_click_selector.
Utilisez des variables d'environnement (ou la configuration de votre framework : config() de Laravel, paramètres de Symfony) en production. Le SDK ne lit pas lui-même les variables d'environnement : c'est délibéré, pour que vous gardiez le contrôle sur la provenance des identifiants. Modèle :
<?php
require 'vendor/autoload.php';
use Crawlbase\CrawlingAPI;
// Pick the right token at instantiation; the SDK doesn't switch
// tokens per-call, so keep two clients if you alternate.
$api = new CrawlingAPI(['token' => getenv('CRAWLBASE_TOKEN')]);
$js = new CrawlingAPI(['token' => getenv('CRAWLBASE_JS_TOKEN')]);
$api->get('https://github.com/anthropic');
$js->get('https://feed.example.com', ['page_wait' => 2000]);Modèle de token complet et emplacements dans le tableau de bord sur la page Authentification.
Démarrage rapide
Trois lignes entre l'autoload et le HTML crawlé :
<?php
require 'vendor/autoload.php';
$api = new \Crawlbase\CrawlingAPI(['token' => 'YOUR_TOKEN']);
$res = $api->get('https://github.com/anthropic');
if ($res->statusCode == 200) {
echo $res->body;
}Branchez sur ->statusCode (le statut HTTP du SDK vers Crawlbase) et ->headers->pc_status (le verdict de Crawlbase : voir Erreurs ci-dessous) pour décider s'il faut réessayer. 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 client correspondante. Même constructeur, mêmes verbes get / post.
<?php
use Crawlbase\{CrawlingAPI, ScraperAPI, LeadsAPI, ScreenshotsAPI, StorageAPI};
$token = ['token' => 'YOUR_TOKEN'];
$crawl = new CrawlingAPI($token); // general-purpose page fetch
$scraper = new ScraperAPI($token); // parsed JSON for supported sites
$leads = new LeadsAPI($token); // domain-scoped email extraction (legacy)
$shots = new ScreenshotsAPI($token); // screenshots of any URL
$storage = new StorageAPI($token); // Cloud Storage CRUD
// 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 SPA, les flux à chargement paresseux et les pages où 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 : une attente fixe, puis network-idle, puis scroll pour le lazy-load, puis click pour tout élément d'UI bloquant.
$api = new \Crawlbase\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 pris en charge. Passez 'scraper' => 'NAME' et le corps de la réponse devient une chaîne JSON avec les champs structurés documentés sur la page de chaque scraper.
<?php
use Crawlbase\ScraperAPI;
$api = new ScraperAPI(['token' => 'YOUR_TOKEN']);
$res = $api->get('https://www.amazon.com/dp/1098145356',
['scraper' => 'amazon-product-details']);
$data = json_decode($res->body, true);
echo $data['name'] . ' - ' . $data['price'];Routage géographique
Passez 'country' => 'ISO' pour router le crawl via les nœuds de sortie de ce pays. À utiliser dès que la cible sert un contenu localisé en fonction de l'IP.
$api = new \Crawlbase\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']);Retry avec backoff
Schéma de retry recommandé : backoff exponentiel plafonné à 3-5 tentatives, retry uniquement sur les erreurs transitoires (5xx ou corps vide), pas de retry sur les 4xx.
<?php
use Crawlbase\CrawlingAPI;
function crawl(CrawlingAPI $api, string $url, int $attempts = 5) {
for ($i = 0; $i < $attempts; $i++) {
$res = $api->get($url);
if ($res->statusCode === 200 && (int) $res->headers->pc_status === 200) {
return $res;
}
if ($res->statusCode >= 400 && $res->statusCode < 500) {
throw new RuntimeException("client error {$res->statusCode}: $url");
}
usleep((int) (mt_rand() / mt_getrandmax() * pow(2, $i) * 1_000_000));
}
throw new RuntimeException("Failed: $url");
}Crawls async + webhooks
Mode fire-and-forget. L'appel SDK retourne immédiatement avec un rid ; Crawlbase envoie le résultat en POST sur votre URL de callback dès que la page est prête. Utile pour les jobs en batch et les cibles lentes.
$api = new \Crawlbase\CrawlingAPI(['token' => 'YOUR_TOKEN']);
$res = $api->get('https://example.com', [
'async' => true,
'callback' => 'https://your-app.com/webhook',
]);
$rid = $res->rid; // correlate the eventual webhook delivery
// Your Laravel / Symfony / Slim webhook receives a POST with:
// { rid, url, original_status, pc_status, body }Pour les très gros volumes (millions d'URLs), utilisez l'Enterprise Crawler qui s'appuie sur ce même pipeline async.
Sessions persistantes
Certains flux nécessitent la même IP résidentielle sur plusieurs appels. Passez cookies_session avec un identifiant stable et Crawlbase réutilise le même nœud de sortie pendant environ 30 minutes.
$api = new \Crawlbase\CrawlingAPI(['token' => 'YOUR_JS_TOKEN']);
$session = "checkout-{$userId}";
$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 expose deux codes de statut sur chaque réponse : le ->statusCode propre au SDK (statut HTTP de la requête vers Crawlbase lui-même) et ->headers->pc_status (verdict de Crawlbase sur la cible : voir le tableau des erreurs de la Crawling API pour la liste complète). Branchez toujours sur ->headers->pc_status pour décider s'il faut réessayer : une cible peut renvoyer 200 avec un corps vide, auquel cas ->statusCode vaut 200 mais ->headers->pc_status vaut 520.
$res = $api->get($url);
$pc = (int) $res->headers->pc_status;
switch (true) {
case $pc === 200:
use_body($res->body);
break;
case in_array($pc, [520, 525], true):
// 520 = empty body, 525 = anti-bot couldn't be solved.
// Switch to JS token and retry.
retry_with_js_token($url);
break;
case in_array($pc, [521, 522, 523], true):
// Target unreachable or timed out. Retry with backoff.
schedule_retry($url);
break;
default:
$logger->error('crawl failed', ['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.
Performance & bonnes pratiques
- Réutilisez un seul client par token. Construisez-le une seule fois au démarrage de l'application (service provider Laravel, conteneur de services Symfony) et injectez-le partout : chaque instance ouvre sa propre connexion.
- Utilisez le token le moins coûteux qui fonctionne. N'utilisez pas le JavaScript token par défaut « 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 un 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. - Pour les jobs en batch : async + webhook, ou poussez vers l'Enterprise Crawler. Des workers de queue qui appellent le SDK de manière synchrone vont saturer votre plafond de concurrence ; async + webhook libère le slot dès qu'une requête est mise en file.
- Surveillez l'en-tête de réponse
remaining. Il indique le nombre de slots de concurrence qu'il vous reste.
Référence des méthodes
Toutes les classes client partagent la même surface. Le constructeur prend un tableau d'options ; les verbes reflètent les méthodes HTTP sous-jacentes.
'timeout' en secondes (par défaut 90).$options associe n'importe quel paramètre de la Crawling API à sa valeur.$data est le body : passez un tableau pour un encodage form, une chaîne pour du brut.Forme de la réponse - propriétés publiques sur l'objet réponse retourné par chaque verbe :
format=json / scraper= a été utilisé).->headers->pc_status: verdict de Crawlbase sur la cible (branchez là-dessus pour les décisions de retry).->headers->original_status: statut HTTP que le site cible a renvoyé à Crawlbase.->headers->storage_url/->headers->rid: renseignés quand l'appel comportait'store' => true.