Se connecter

Comment le SDK est structuré

Le SDK Go est volontairement minimaliste. Un seul client, CrawlingAPI, couvre tous les produits Crawlbase via le endpoint unifié de la Crawling API :

Cas d'usageÀ passer dans options
Crawl simple(rien : c'est le comportement par défaut)
Scraper intégré"scraper": "amazon-product-details" (et le reste du catalogue)
Capture d'écran"screenshot": "true"
Extraction d'e-mails"scraper": "email-extractor"
Async + webhook"async": "true" + "callback": "https://..."
Envoi vers l'Enterprise Crawler"async": "true" + "callback" + "crawler": "YourCrawler"

Les endpoints autonomes /scraper, /leads et /screenshots (que les anciens SDK Crawlbase encapsulaient avec des classes client distinctes) sont fermés aux nouvelles inscriptions depuis 2024. Le SDK Go n'expose que la voie moderne : un seul client, tous les produits, aucune classe vestigiale.

Ce que vous gagnez en l'utilisant plutôt que net/http directement :

  • Encodage d'URL, validation des paramètres et parsing des réponses gérés d'office.
  • Surface Go idiomatique : retours (result, error), champs de struct nommés, pas de panics en cas d'échec de transport.
  • Prise en charge de context.Context sur chaque verbe via les variantes *WithContext pour l'annulation / les délais / la propagation de trace.
  • Valeurs par défaut sensées (timeout de 90 secondes, décompression gzip transparente, parsing JSON automatique des réponses format=json / scraper=).

Source sur github.com/crawlbase/crawlbase-go. Référence sur pkg.go.dev. Issues et PRs bienvenues.

Installation

Dernière version sur pkg.go.dev. Requiert Go 1.21+.

go get github.com/crawlbase/crawlbase-go@latest

# Or pin a specific version
go get github.com/crawlbase/[email protected]

Authentification

Toutes les API Crawlbase s'authentifient avec le même modèle de token. Deux types de token coexistent sur un seul compte :

  • Normal Token (TCP) - pour le HTML statique, les endpoints JSON, tout ce qui n'a pas besoin d'un navigateur. Plus rapide et moins cher.
  • JavaScript Token - pour les SPAs, les flux à chargement différé, tout ce qui masque du contenu derrière un rendu côté client. Requis pour utiliser page_wait, ajax_wait, scroll et css_click_selector.

En production, utilisez des variables d'environnement. Le SDK ne lit pas lui-même les variables d'environnement : c'est volontaire, pour que vous gardiez le contrôle de la provenance de vos identifiants. Schéma :

package main

import (
 "log"
 "os"

 "github.com/crawlbase/crawlbase-go"
)

func main() {
 // Pick the right token at instantiation; the SDK doesn't switch
 // tokens per-call, so keep two clients if you alternate.
 api, err := crawlbase.NewCrawlingAPI(os.Getenv("CRAWLBASE_TOKEN"))
 if err != nil {
 log.Fatal(err)
 }
 js, err := crawlbase.NewCrawlingAPI(os.Getenv("CRAWLBASE_JS_TOKEN"))
 if err != nil {
 log.Fatal(err)
 }

 api.Get("https://github.com/anthropic", nil)
 js.Get("https://feed.example.com", map[string]string{"page_wait": "2000"})
}

Le constructeur retourne crawlbase.ErrTokenRequired si la chaîne du token est vide. Modèle de token complet et emplacements dans le tableau de bord sur la page Authentification.

Démarrage rapide

Trois lignes de l'import au HTML crawlé :

package main

import (
 "fmt"
 "log"

 "github.com/crawlbase/crawlbase-go"
)

func main() {
 api, err := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
 if err != nil {
 log.Fatal(err)
 }
 res, err := api.Get("https://github.com/anthropic", nil)
 if err != nil {
 log.Fatal(err)
 }
 if res.StatusCode == 200 {
 fmt.Println(res.Body)
 }
}

Branchez sur res.StatusCode (le statut HTTP du SDK vers Crawlbase) et res.PCStatus (le verdict de Crawlbase, voir Erreurs ci-dessous) lorsque vous décidez de réessayer ou non. Passez map[string]string{"format": "json"} pour recevoir une enveloppe JSON plutôt que le contenu brut de la page (auto-parsée dans res.JSON).

Schémas courants

Rendu JavaScript

Pour les SPAs, les flux à chargement paresseux 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 : une attente fixe, puis l'inactivité réseau, puis le scroll pour le chargement paresseux, puis le clic pour tout élément d'UI bloquant.

api, _ := crawlbase.NewCrawlingAPI("YOUR_JS_TOKEN")
res, err := api.Get("https://spa.example.com", map[string]string{
 "page_wait": "2000",
 "ajax_wait": "true",
 "scroll": "true",
})

Utiliser un scraper intégré

Sautez complètement le parser sur les sites supportés. Passez "scraper": "NAME" et le Body de la réponse devient une chaîne JSON avec les champs structurés documentés sur la page de chaque scraper. Le body est également pré-décodé dans res.JSON, ce qui vous permet de lire les champs directement.

api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
res, err := api.Get(
 "https://www.amazon.com/dp/1098145356",
 map[string]string{"scraper": "amazon-product-details"},
)
if err != nil {
 log.Fatal(err)
}

if name, ok := res.JSON["name"].(string); ok {
 fmt.Println(name)
}

Routage géographique

Passez "country": "ISO" pour router le crawl par les nœuds de sortie de ce pays. À utiliser dès que la cible sert du contenu localisé en fonction de l'IP.

api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")

// Hit the German Amazon catalog from a German residential IP
res, _ := api.Get(
 "https://www.amazon.com/dp/1098145356",
 map[string]string{"country": "DE"},
)

Retry avec backoff

Le schéma de retry recommandé : backoff exponentiel plafonné à 3-5 tentatives, retry uniquement sur les erreurs transitoires (5xx ou body vide), pas de retry sur les 4xx.

import (
 "fmt"
 "math"
 "math/rand"
 "time"

 "github.com/crawlbase/crawlbase-go"
)

func Crawl(api *crawlbase.CrawlingAPI, url string, attempts int) (*crawlbase.Response, error) {
 for i := 0; i < attempts; i++ {
 res, err := api.Get(url, nil)
 if err != nil {
 return nil, err
 }
 if res.StatusCode == 200 && res.PCStatus == 200 {
 return res, nil
 }
 if res.StatusCode >= 400 && res.StatusCode < 500 {
 return nil, fmt.Errorf("client error %d: %s", res.StatusCode, url)
 }
 // Exponential backoff with jitter
 d := time.Duration(rand.Float64() * math.Pow(2, float64(i)) * float64(time.Second))
 time.Sleep(d)
 }
 return nil, fmt.Errorf("failed: %s", url)
}

Crawls async + webhooks

Mode fire-and-forget. L'appel SDK retourne immédiatement avec un RID ; Crawlbase fait un POST du résultat sur votre URL de callback dès que la page est prête. Utile pour les jobs batch et les cibles lentes.

api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")
res, _ := api.Get("https://example.com", map[string]string{
 "async": "true",
 "callback": "https://your-app.com/webhook",
})
rid := res.RID // correlate the eventual webhook delivery

// Your net/http handler receives a POST with:
// { rid, url, original_status, pc_status, body }

Pour de très gros volumes (des millions d'URLs), envoyez vers l'Enterprise Crawler en ajoutant "crawler": "YourCrawlerName" aux options async + callback.

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 ~30 minutes.

api, _ := crawlbase.NewCrawlingAPI("YOUR_JS_TOKEN")

session := fmt.Sprintf("checkout-%d", userID)
opts := map[string]string{"cookies_session": session}

api.Get("https://shop.example.com/cart", opts)
api.Get("https://shop.example.com/checkout", opts)
api.Get("https://shop.example.com/confirm", opts)

Captures d'écran

Passez "screenshot": "true" pour capturer une capture d'écran de la page entière. Le body revient sous forme d'image encodée en base64 ; utilisez crawlbase.ImageBytes(res) pour la décoder en octets bruts pour os.WriteFile / image.Decode.

api, _ := crawlbase.NewCrawlingAPI("YOUR_JS_TOKEN")
res, _ := api.Get("https://www.apple.com", map[string]string{
 "screenshot": "true",
})

img, err := crawlbase.ImageBytes(res)
if err != nil {
 log.Fatal(err)
}
os.WriteFile("apple.png", img, 0o644)

Context pour l'annulation

Chaque verbe dispose d'une variante *WithContext à utiliser avec context.Context : utile dès que l'appel doit respecter une annulation amont, une échéance ou la propagation de trace (handlers HTTP, serveurs gRPC, tout ce qui s'exécute dans une boucle de requêtes).

import (
 "context"
 "time"
)

api, _ := crawlbase.NewCrawlingAPI("YOUR_TOKEN")

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

res, err := api.GetWithContext(ctx, "https://example.com", nil)

Erreurs & retries

La plateforme expose deux codes de statut sur chaque réponse : le res.StatusCode propre au SDK (statut HTTP de la requête vers Crawlbase lui-même) et res.PCStatus (le verdict de Crawlbase sur la cible, extrait de l'en-tête de réponse pc_status pour un accès typé ; voir la table des erreurs de la Crawling API pour la liste complète). Branchez toujours sur PCStatus pour décider de réessayer : une cible peut renvoyer 200 avec un corps vide, auquel cas StatusCode vaut 200 mais PCStatus vaut 520.

res, err := api.Get(url, nil)
if err != nil {
 return err
}

switch res.PCStatus {
case 200:
 use(res.Body)
case 520, 525:
 // 520 = empty body, 525 = anti-bot couldn't be solved.
 // Switch to JS token and retry.
 retryWithJSToken(url)
case 521, 522, 523:
 // Target unreachable or timed out. Retry with backoff.
 scheduleRetry(url)
default:
 log.Printf("crawl failed: url=%s pc_status=%d", url, res.PCStatus)
}

Tous les retries contre la plateforme sont gratuits : seules les réponses réussies (PCStatus: 200) sont décomptées de votre quota.

Performance & bonnes pratiques

  • Réutilisez un seul client par token. Le constructeur est peu coûteux, mais chaque instance *CrawlingAPI possède son propre http.Client sous-jacent avec son propre pool de connexions. Construisez-le une fois à l'initialisation du service, partagez-le entre les goroutines (le SDK est goroutine-safe).
  • Utilisez le token le moins coûteux qui fonctionne. Ne basculez pas sur le JavaScript token « au cas où » par défaut : les requêtes avec Normal token sont plus rapides et consomment moins de concurrence. Passez au token supérieur sur un PCStatus == 520 ou 525.
  • 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 batch : async + webhook, ou push vers l'Enterprise Crawler. Des pools de goroutines bloquant sur des appels synchrones saturent rapidement les plafonds de concurrence ; async + webhook libère le slot dès qu'une requête est mise en file.
  • Utilisez GetWithContext / PostWithContext dans le code serveur. Un context lié à la requête propage l'annulation lorsque l'appelant disparaît : sans cela, un crawl bloqué continuera au-delà de l'échéance de l'appelant.

Champs de réponse

Les signatures de méthode complètes, la godoc et des exemples par méthode sont disponibles sur pkg.go.dev. Les champs ci-dessous sont ceux que les utilisateurs Crawlbase consultent le plus : le verdict typé sur la cible, renvoyé sur chaque *crawlbase.Response :

StatusCode
int
Statut HTTP de la requête du SDK vers Crawlbase.
PCStatus
int
Verdict de Crawlbase sur la cible. Extrait de l'en-tête de réponse pc_status (ou cb_status) pour un accès typé. Branchez sur ce champ pour les décisions de retry.
OriginalStatus
int
Statut HTTP retourné par le site cible à Crawlbase.
URL
string
URL finale après les redirections côté cible.
Body
string
Contenu de la page (ou chaîne JSON quand format=json / scraper= a été utilisé ; ou image encodée en base64 quand screenshot=true).
Headers
map[string]string
En-têtes de réponse en minuscules.
RID
string
Request ID : défini lorsque l'appel comportait "async": "true" ou "store": "true".
JSON
map[string]any
JSON pré-parsé quand le Content-Type de la réponse est JSON. Évite une étape json.Unmarshal sur les appels scraper / format=json.