Войти

Как устроен SDK

Go SDK намеренно минималистичен. Один клиент, CrawlingAPI, охватывает все продукты Crawlbase через единый endpoint Crawling API:

Сценарий использованияПередать в options
Обычный обход(ничего, значение по умолчанию)
Встроенный скрейпер"scraper": "amazon-product-details" (и остальные из каталога)
Скриншот"screenshot": "true"
Извлечение email"scraper": "email-extractor"
Async + webhook"async": "true" + "callback": "https://..."
Отправка в Enterprise Crawler"async": "true" + "callback" + "crawler": "YourCrawler"

Отдельные endpoint'ы /scraper, /leads и /screenshots (которые старые Crawlbase SDK оборачивают отдельными классами клиентов) закрыты для новых регистраций с 2024 года. Go SDK поставляется только с современным путём: один клиент, все продукты, никаких рудиментарных классов.

Что вы получаете, используя его вместо net/http напрямую:

  • URL-кодирование, валидация параметров и парсинг ответов — из коробки.
  • Идиоматичная поверхность Go: возврат (result, error), именованные поля структур, никаких panic при сбоях транспорта.
  • Поддержка context.Context в каждом методе через варианты *WithContext для отмены / дедлайнов / распространения трассировки.
  • Разумные значения по умолчанию (таймаут 90 секунд, прозрачная распаковка gzip, автоматический парсинг JSON для ответов format=json / scraper=).

Исходники на github.com/crawlbase/crawlbase-go. Справочник на pkg.go.dev. Issues и PR приветствуются.

Установка

Последняя версия на pkg.go.dev. Требуется Go 1.21+.

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

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

Аутентификация

Все API Crawlbase используют одну и ту же модель токенов. На одном аккаунте существует два типа токенов:

  • Normal Token (TCP) - для статического HTML, JSON-эндпоинтов, всего, что не требует браузера. Быстрее и дешевле.
  • JavaScript Token - для SPA, лениво загружаемых лент, всего, что скрывает контент за клиентским рендерингом. Требуется для использования page_wait, ajax_wait, scroll и css_click_selector.

В продакшене используйте переменные окружения. SDK сам не читает env-переменные, это сделано намеренно, чтобы вы сохраняли контроль над тем, откуда берутся учётные данные. Шаблон:

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"})
}

Конструктор возвращает crawlbase.ErrTokenRequired, если строка токена пуста. Полная модель токенов и расположение в дашборде — на странице Аутентификация.

Быстрый старт

Три строки от импорта до полученного 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)
 }
}

Ветвитесь по res.StatusCode (HTTP-статус SDK к Crawlbase) и res.PCStatus (вердикт Crawlbase, см. Ошибки ниже), когда решаете, повторять ли запрос. Передайте map[string]string{"format": "json"}, чтобы получить JSON-конверт вместо сырого содержимого страницы (автоматически разбирается в res.JSON).

Распространённые шаблоны

JavaScript-рендеринг

Для SPA, лениво подгружаемых лент и страниц с пустым начальным HTML создавайте экземпляр с JavaScript token и передавайте любую комбинацию из page_wait, ajax_wait, scroll и css_click_selector. Порядок, о котором стоит подумать: фиксированное ожидание, затем network-idle, затем scroll для ленивой загрузки, затем click для любого блокирующего UI-элемента.

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",
})

Использование встроенного скрейпера

Полностью пропустите парсер на поддерживаемых сайтах. Передайте "scraper": "NAME", и тело ответа станет JSON-строкой со структурированными полями, описанными на странице конкретного скрейпера. Тело также предварительно декодируется в res.JSON, чтобы вы могли читать поля напрямую.

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)
}

Гео-маршрутизация

Передайте "country": "ISO", чтобы направить обход через выходные узлы соответствующей страны. Используйте всегда, когда целевой сайт отдаёт локализованный контент в зависимости от 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"},
)

Повторные попытки с backoff

Рекомендуемая схема повторов: экспоненциальный backoff с ограничением 3–5 попыток, повтор только при временных ошибках (5xx или пустое тело), без повторов при 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-обходы + webhooks

Режим fire-and-forget. Вызов SDK сразу возвращается с RID; Crawlbase отправляет результат POST-запросом на ваш callback URL, когда страница готова. Полезно для пакетных задач и медленных целевых сайтов.

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 }

Для очень больших объёмов (миллионы URL) отправляйте задачи в Enterprise Crawler, добавив "crawler": "YourCrawlerName" вместе с опциями async + callback.

Sticky-сессии

Некоторым сценариям нужен один и тот же резидентский IP на протяжении нескольких вызовов. Передайте cookies_session со стабильным идентификатором, и Crawlbase будет переиспользовать тот же выходной узел в течение примерно 30 минут.

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)

Скриншоты

Передайте "screenshot": "true", чтобы сделать снимок всей страницы. Тело возвращается как изображение, закодированное в base64; используйте crawlbase.ImageBytes(res) для декодирования в сырые байты для 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 для отмены

У каждого метода есть вариант *WithContext для использования с context.Context: полезно всякий раз, когда вызов должен учитывать отмену сверху, дедлайны или распространение трассировок (HTTP-обработчики, gRPC-серверы, всё, что находится в цикле запросов).

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)

Ошибки & повторы

Платформа возвращает два кода состояния в каждом ответе: собственный res.StatusCode SDK (HTTP-статус запроса к самой Crawlbase) и res.PCStatus (вердикт Crawlbase по целевой странице, извлечённый из заголовка ответа pc_status для типизированного доступа; полный список см. в таблице ошибок Crawling API). Всегда ветвитесь по PCStatus, когда решаете, повторять ли запрос: цель может вернуть 200 с пустым телом, в этом случае StatusCode равен 200, но PCStatus равен 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)
}

Все повторные запросы к платформе бесплатны: только успешные ответы (PCStatus: 200) учитываются в вашей квоте.

Производительность & лучшие практики

  • Переиспользуйте один клиент на token. Конструктор дешёвый, но каждый экземпляр *CrawlingAPI имеет собственный http.Client со своим пулом соединений. Создавайте его один раз при инициализации сервиса и используйте совместно во всех горутинах (SDK потокобезопасен).
  • Используйте самый дешёвый token, который работает. Не используйте JavaScript token по умолчанию «на всякий случай»: запросы с Normal token быстрее и используют меньше параллелизма. Повышайте уровень при PCStatus == 520 или 525.
  • Предпочитайте ajax_wait вместо page_wait. Фиксированные задержки расходуют параллелизм на каждом запросе, даже на быстрых.
  • Для пакетных задач: async + webhook или отправка в Enterprise Crawler. Пулы горутин, блокирующиеся на синхронных вызовах, быстро упираются в лимиты параллелизма; async + webhook освобождает слот в момент постановки запроса в очередь.
  • Используйте GetWithContext / PostWithContext в серверном коде. Context уровня запроса распространяет отмену, когда вызывающая сторона уходит: без него зависший обход будет продолжаться после дедлайна вызывающей стороны.

Поля ответа

Полные сигнатуры методов, godoc и примеры по каждому методу живут на pkg.go.dev. Поля ниже, к которым пользователи Crawlbase обращаются чаще всего: типизированный вердикт по цели, возвращаемый в каждом *crawlbase.Response:

StatusCode
int
HTTP-статус запроса SDK к Crawlbase.
PCStatus
int
Вердикт Crawlbase по целевому сайту. Извлекается из заголовка ответа pc_status (или cb_status) для типизированного доступа. Принимайте решение о повторе на основе этого поля.
OriginalStatus
int
HTTP-статус, который целевой сайт вернул Crawlbase.
URL
string
Итоговый URL после редиректов на стороне целевого сайта.
Body
string
Содержимое страницы (или JSON-строка, если использовался format=json / scraper=; или изображение в base64, если использовался screenshot=true).
Headers
map[string]string
Заголовки ответа в нижнем регистре.
RID
string
Request ID: устанавливается, когда вызов содержал "async": "true" или "store": "true".
JSON
map[string]any
Предварительно распарсенный JSON, когда Content-Type ответа — JSON. Избавляет от шага json.Unmarshal для вызовов scraper / format=json.