Go
Client Go officiel pour la plateforme Crawlbase. Go idiomatique : retours d'erreur plutôt qu'exceptions, prise en charge de context.Context sur chaque verbe, zéro dépendance externe (uniquement net/http + stdlib).
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.Contextsur chaque verbe via les variantes*WithContextpour 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,scrolletcss_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
*CrawlingAPIpossède son proprehttp.Clientsous-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 == 520ou525. - 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/PostWithContextdans 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 :
pc_status (ou cb_status) pour un accès typé. Branchez sur ce champ pour les décisions de retry.format=json / scraper= a été utilisé ; ou image encodée en base64 quand screenshot=true)."async": "true" ou "store": "true".json.Unmarshal sur les appels scraper / format=json.