Go
Offizieller Go-Client für die Crawlbase-Plattform. Idiomatisches Go: error-Rückgaben statt Exceptions, context.Context-Unterstützung bei jeder Methode, keine externen Abhängigkeiten (nur net/http + stdlib).
Wie das SDK aufgebaut ist
Das Go SDK ist bewusst schlank gehalten. Ein Client, CrawlingAPI, deckt jedes Crawlbase-Produkt über den einheitlichen Crawling API Endpoint ab:
| Anwendungsfall | In options übergeben |
|---|---|
| Einfacher Crawl | (nichts, der Standard) |
| Integrierter Scraper | "scraper": "amazon-product-details" (und der Rest des Katalogs) |
| Screenshot | "screenshot": "true" |
| E-Mail-Extraktion | "scraper": "email-extractor" |
| Async + Webhook | "async": "true" + "callback": "https://..." |
| An Enterprise Crawler übergeben | "async": "true" + "callback" + "crawler": "YourCrawler" |
Die eigenständigen Endpoints /scraper, /leads und /screenshots (die ältere Crawlbase SDKs mit separaten Client-Klassen umhüllen) sind seit 2024 für Neuanmeldungen geschlossen. Das Go SDK liefert nur den modernen Weg: ein Client, jedes Produkt, keine Altlasten-Klassen.
Was Sie davon haben, es statt net/http direkt zu verwenden:
- URL-Encoding, Parameter-Validierung und Response-Parsing werden out of the box erledigt.
- Idiomatische Go-Oberfläche:
(result, error)-Rückgaben, benannte Struct-Felder, keine Panics bei Transport-Fehlern. context.Context-Unterstützung bei jedem Verb über*WithContext-Varianten für Cancellation / Deadlines / Trace-Propagation.- Sinnvolle Standardwerte (90 Sekunden Timeout, transparente gzip-Dekompression, automatisches JSON-Parsing von
format=json- /scraper=-Responses).
Quellcode auf github.com/crawlbase/crawlbase-go. Referenz auf pkg.go.dev. Issues + PRs willkommen.
Installation
Aktuelle Version auf pkg.go.dev. Erfordert Go 1.21+.
go get github.com/crawlbase/crawlbase-go@latest
# Or pin a specific version
go get github.com/crawlbase/[email protected]Authentifizierung
Jede Crawlbase API authentifiziert sich mit demselben Token-Modell. Zwei Token-Typen existieren in einem einzigen Konto:
- Normal Token (TCP) - für statisches HTML, JSON-Endpoints, alles, was keinen Browser benötigt. Schneller + günstiger.
- JavaScript Token
- für SPAs, Lazy-Loaded Feeds, alles, was Inhalte hinter clientseitigem Rendering verbirgt. Erforderlich für die Nutzung von
page_wait,ajax_wait,scrollundcss_click_selector.
Verwenden Sie in der Produktion Umgebungsvariablen. Das SDK liest die env-Variablen nicht selbst, das ist Absicht, damit Sie die Kontrolle darüber behalten, woher die Credentials kommen. Muster:
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"})
}Der Konstruktor gibt crawlbase.ErrTokenRequired zurück, wenn der Token-String leer ist. Vollständiges Token-Modell + Dashboard-Speicherorte auf der Seite Authentifizierung.
Schnellstart
Drei Zeilen vom Import zum gecrawlten HTML:
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)
}
}Verzweigen Sie über res.StatusCode (HTTP-Status des SDK gegenüber Crawlbase) und res.PCStatus (das Crawlbase-Urteil, siehe Errors unten), wenn Sie entscheiden, ob ein Retry erfolgen soll. Übergeben Sie map[string]string{"format": "json"}, um statt rohem Seiteninhalt eine JSON-Hülle zu erhalten (automatisch in res.JSON geparst).
Häufige Muster
JavaScript-Rendering
Für SPAs, lazy-geladene Feeds und Seiten, bei denen das initiale HTML leer ist, instanziieren Sie mit dem JavaScript token und übergeben eine beliebige Kombination aus page_wait, ajax_wait, scroll und css_click_selector. Sinnvolle Reihenfolge: ein fester Wait, dann Network-Idle, dann Scroll für Lazy-Load, dann Click für ein eventuelles Gating-UI-Element.
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",
})Einen integrierten Scraper verwenden
Sparen Sie sich den Parser auf unterstützten Seiten komplett. Übergeben Sie "scraper": "NAME", und der Response-Body wird zu einem JSON-String mit den strukturierten Feldern, die auf der jeweiligen Scraper-Seite dokumentiert sind. Der Body wird zusätzlich in res.JSON vorab dekodiert, sodass Sie die Felder direkt auslesen können.
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)
}Geo-Routing
Übergeben Sie "country": "ISO", um den Crawl über die Exit-Nodes des jeweiligen Landes zu leiten. Verwenden Sie das immer dann, wenn das Ziel basierend auf der IP lokalisierten Content ausliefert.
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 mit Backoff
Empfohlene Retry-Form: exponentielles Backoff, gedeckelt auf 3-5 Versuche, Retry nur bei transienten Fehlern (5xx oder leerer Body), kein Retry bei 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)
}Async-Crawls + Webhooks
Fire-and-forget-Modus. Der SDK-Aufruf kehrt sofort mit einer RID zurück; Crawlbase POSTet das Ergebnis an Ihre Callback-URL, sobald die Seite bereit ist. Nützlich für Batch-Jobs und langsame Ziele.
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 }Für sehr hohe Volumen (Millionen von URLs) übergeben Sie an den Enterprise Crawler, indem Sie "crawler": "YourCrawlerName" zusätzlich zu den async- + callback-Optionen ergänzen.
Sticky Sessions
Manche Flows benötigen dieselbe Residential-IP über mehrere Aufrufe hinweg. Übergeben Sie cookies_session mit einem stabilen Identifier, und Crawlbase verwendet rund 30 Minuten lang denselben Exit-Node weiter.
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)Screenshots
Übergeben Sie "screenshot": "true", um einen ganzseitigen Screenshot zu erfassen. Der Body kommt als base64-kodiertes Bild zurück; verwenden Sie crawlbase.ImageBytes(res), um in rohe Bytes für os.WriteFile / image.Decode zu dekodieren.
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 für Cancellation
Jede Methode hat eine *WithContext-Variante zur Nutzung mit context.Context: nützlich, wann immer der Aufruf Upstream-Cancellation, Deadlines oder Trace-Propagation respektieren soll (HTTP-Handler, gRPC-Server, alles in einer Request-Schleife).
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)Errors & Retries
Die Plattform liefert bei jeder Response zwei Statuscodes: den eigenen res.StatusCode des SDK (HTTP-Status der Anfrage an Crawlbase selbst) und res.PCStatus (Crawlbases Urteil über das Ziel, herausgelöst aus dem pc_status-Response-Header für typisierten Zugriff; die vollständige Liste finden Sie in der Crawling API Errors-Tabelle). Verzweigen Sie immer über PCStatus, wenn Sie entscheiden, ob ein Retry erfolgen soll: Ein Ziel kann 200 mit leerem Body zurückgeben, in welchem Fall StatusCode 200 ist, PCStatus aber 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)
}Alle Retries gegen die Plattform sind kostenlos: nur erfolgreiche Responses (PCStatus: 200) werden auf Ihr Kontingent angerechnet.
Performance & Best Practices
- Verwenden Sie einen einzigen Client pro Token wieder.
Der Konstruktor ist günstig, aber jede
*CrawlingAPI-Instanz hat ihren eigenenhttp.Clientmit eigenem Connection-Pool. Erstellen Sie ihn einmal beim Service-Init und teilen Sie ihn über alle Goroutines hinweg (das SDK ist goroutine-safe). - Nutzen Sie das günstigste Token, das funktioniert.
Greifen Sie nicht standardmäßig zum JavaScript token «für alle Fälle»: Anfragen mit dem Normal token sind schneller und benötigen weniger Concurrency. Eskalieren Sie bei einem
PCStatus == 520oder525. - Bevorzugen Sie
ajax_waitgegenüberpage_wait. Feste Delays verbrauchen bei jedem Request Concurrency, auch bei schnellen. - Für Batch-Jobs: async + Webhook oder Push an den Enterprise Crawler. Goroutine-Pools, die auf synchronen Aufrufen blockieren, lasten Concurrency-Caps schnell aus; async + Webhook gibt den Slot frei, sobald ein Request in die Queue gestellt wurde.
- Verwenden Sie
GetWithContext/PostWithContextin Server-Code. Ein request-bezogener Context propagiert Cancellation, wenn der Caller wegfällt: ohne ihn läuft ein hängender Crawl über die Deadline des Callers hinaus weiter.
Response-Felder
Vollständige Methodensignaturen, godoc und Beispiele pro Methode finden Sie auf pkg.go.dev. Die folgenden Felder sind der Teil, nach dem Crawlbase-Nutzer am häufigsten greifen: das typisierte Urteil über das Ziel, zurückgegeben bei jeder *crawlbase.Response:
pc_status (oder cb_status) für typisierten Zugriff extrahiert. Verzweigen Sie hierauf für Retry-Entscheidungen.format=json / scraper= verwendet wurde; oder base64-kodiertes Bild bei screenshot=true)."async": "true" oder "store": "true" enthielt.json.Unmarshal-Schritt.