Войти

Как устроен SDK

Python SDK - это тонкая обёртка с минимумом зависимостей вокруг того же HTTP API, который описан в API Reference. Каждый параметр Crawling API, который вы бы добавили в виде query-строки при сыром HTTP-вызове, доступен из SDK как ключ в словаре options - имена, значения по умолчанию и поведение совпадают один-к-одному. SDK не добавляет ни одного параметра; SDK не скрывает ни одного параметра.

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

  • URL-кодирование, валидация параметров и парсинг ответа из коробки - код вашего приложения читается как продуктовый код, а не как HTTP-сантехника.
  • По одному классу клиента на каждый Crawlbase API, все с одинаковой формой конструктора и вызова — освоив один, вы освоили их все.
  • Разумные значения по умолчанию (90-секундный таймаут, парсинг JSON для ответов format=json, автоматическое декодирование UTF-8), которые большинство команд настраивает вручную при первой интеграции.
  • Небольшая поверхность для изучения - пять классов клиента, два глагола (get / post), одна форма ответа.

SDK имеет открытый исходный код под лицензией MIT и принимает PR от сообщества на github.com/crawlbase/crawlbase-python. Большинство сообщённых проблем попадает в релиз в течение спринта.

Установка

Последняя версия на PyPI. Требуется Python 3.7+; протестировано вплоть до Python 3.13.

pip install crawlbase

# Or via Poetry / uv / pip-tools
poetry add crawlbase
uv add crawlbase

Исходники на GitHub. Issues и PR приветствуются.

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

Каждый Crawlbase API аутентифицируется по одной и той же модели токенов - отдельного API-ключа на каждый продукт нет. На одном аккаунте живут два типа токенов:

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

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

import os
from crawlbase import CrawlingAPI

# Pick the right token at instantiation; the SDK doesn't switch
# tokens per-call, so keep two clients if you alternate.
api = CrawlingAPI({'token': os.environ['CRAWLBASE_TOKEN']})
js  = CrawlingAPI({'token': os.environ['CRAWLBASE_JS_TOKEN']})

res = api.get('https://github.com/anthropic')
res = js.get('https://feed.example.com', {'page_wait': 2000})

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

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

Три строки от import до полученного HTML:

from crawlbase import CrawlingAPI

api = CrawlingAPI({'token': 'YOUR_TOKEN'})
res = api.get('https://github.com/anthropic')

if res['status_code'] == 200:
    print(res['body'])

Ветвитесь по status_code (HTTP-статус запроса SDK к Crawlbase) и pc_status (вердикт Crawlbase - см. Ошибки ниже) при принятии решения о повторе. Тело по умолчанию - bytes; передайте 'format': 'json', чтобы получить JSON-конверт вместо сырого содержимого страницы.

Все APIs в одном пакете

Каждому Crawlbase API соответствует свой класс клиента. Один и тот же конструктор, одни и те же глаголы get / post. Класс выбирается по тому, что вы делаете; под капотом все они обращаются к разным эндпоинтам одной и той же платформы.

from crawlbase import (
    CrawlingAPI,    # general-purpose page fetch (HTML / JSON / etc.)
    ScraperAPI,     # parsed JSON for supported sites (Amazon, Google, etc.)
    LeadsAPI,       # domain-scoped email extraction (legacy)
    ScreenshotsAPI, # screenshots of any URL
    StorageAPI,     # Cloud Storage CRUD
)

token = {'token': 'YOUR_TOKEN'}

crawl   = CrawlingAPI(token)
scraper = ScraperAPI(token)
leads   = LeadsAPI(token)
shots   = ScreenshotsAPI(token)
storage = StorageAPI(token)

# 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.

Типовые паттерны

JavaScript-рендеринг

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

api = CrawlingAPI({'token': 'YOUR_JS_TOKEN'})
res = api.get('https://spa.example.com', {
    'page_wait': 2000,
    'ajax_wait': True,
    'scroll': True,
})

Используйте встроенный scraper

На поддерживаемых сайтах парсер не нужен вовсе. Передайте 'scraper': 'NAME', и body ответа станет JSON-строкой со структурированными полями, описанными на странице конкретного scraper'а.

import json
from crawlbase import ScraperAPI

api = ScraperAPI({'token': 'YOUR_TOKEN'})
res = api.get(
    'https://www.amazon.com/dp/1098145356',
    {'scraper': 'amazon-product-details'}
)
data = json.loads(res['body'])
print(data['name'], data['price'])

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

Передайте 'country'='ISO', чтобы направить краулинг через выходные ноды этой страны. Используйте это всякий раз, когда цель отдаёт локализованный контент в зав��симости от IP - большинство ритейлеров, все SERP, гео-ограниченные страницы стриминга.

api = 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'}
)

Async с повторами

Рекомендуемая форма повторов: экспоненциальная задержка с потолком в 3-5 попыток, повтор только для временных ошибок (5xx или пустое тело), без повторов на 4xx (форма запроса некорректна и сама не починится).

import time, random
from crawlbase import CrawlingAPI

api = CrawlingAPI({'token': 'YOUR_TOKEN'})

def crawl(url, attempts=5):
    for i in range(attempts):
        res = api.get(url)
        # 200 from Crawlbase + non-empty body from the target
        if res['status_code'] == 200 and int(res.get('pc_status', 0)) == 200:
            return res
        # Don't bother retrying client errors (4xx)
        if 400 <= res['status_code'] < 500:
            raise ValueError(f"client error {res['status_code']}: {url}")
        # Exponential backoff with jitter
        time.sleep(random.uniform(0, 2 ** i))
    raise RuntimeError(f'Failed: {url}')

Async-обходы и вебхуки

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

api = CrawlingAPI({'token': 'YOUR_TOKEN'})
res = api.get('https://example.com', {
    'async': True,
    'callback': 'https://your-app.com/webhook',
})
rid = res['rid']  # use this to correlate the eventual webhook delivery

# Webhook handler (Flask / FastAPI / etc.) receives a POST with:
#   { rid, url, original_status, pc_status, body }

Для очень больших объёмов (миллионы URL) используйте Enterprise Crawler, который стоит перед этим же async-пайплайном и обеспечивает повторы, управление частотой и доставку результатов.

Залипающие сессии

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

api = CrawlingAPI({'token': 'YOUR_JS_TOKEN'})

session = f'checkout-{user_id}'
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})

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

Платформа Crawlbase возвращает в каждом ответе два статус-кода: собственный status_code SDK (HTTP-статус запроса к самому Crawlbase) и pc_status (вердикт Crawlbase по цели - полный список см. в таблице ошибок Crawling API). Всегда ветвитесь по pc_status при принятии решения о повторе - цель может вернуть 200 с пустым телом, в этом случае status_code равен 200, а pc_status равен 520.

res = api.get(url)
pc = int(res.get('pc_status', 0))

if pc == 200:
    use(res['body'])
elif pc in (520, 525):
    # 520 = empty body, 525 = anti-bot couldn't be solved.
    # Switch to JS token and retry.
    retry_with_js_token(url)
elif pc in (521, 522, 523):
    # Target unreachable or timed out. Retry with backoff.
    schedule_retry(url)
else:
    log.error('crawl failed', extra={'url': url, 'pc_status': pc})

Все повторы к платформе бесплатны - в счёт вашей квоты идут только успешные ответы (pc_status: 200). Это делает агрессивный backoff дешёвым; единственная реальная цена повторов - дополнительная задержка.

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

  • Переиспользуйте один клиент на токен. Конструктор дёшев, но каждый экземпляр открывает собственный пул соединений. Создайте его один раз на уровне модуля и используйте для всех вызовов.
  • Используйте самый дешёвый токен, который работает. Не используйте JavaScript token по умолчанию «на всякий случай» - запросы с Normal-токеном быстрее и используют меньше конкурентности. Переходите на JS только тогда, когда ответ Normal пуст или заблокирован антиботом.
  • Предпочитайте ajax_wait, а не page_wait. Фиксированные задержки сжигают конкурентность на каждом запросе, даже быстром. ajax_wait возвращает результат в момент, когда страница достигает network-idle.
  • Для пакетных задач: async + вебхук или отправка в Enterprise Crawler. Синхронный режим — правильный выбор по умолчанию для разовых и интерактивных задач; для устойчивой высокообъёмной отправки переключайтесь на async, чтобы слот конкурентности освобождался в момент постановки запроса в очередь, а не по его завершении.
  • Следите за заголовком ответа remaining. Он несёт количество оставшихся у вас слотов конкурентности - здоровый клиент проактивно сбавляет темп до достижения лимита, а не реагирует на 429.

Справочник методов

Все классы клиентов имеют одинаковый интерфейс. Конструктор принимает один словарь options; методы отражают соответствующие HTTP-методы.

CrawlingAPI({'token': T, 'timeout': N})
конструктор
Инициализирует клиент с вашим токеном. Опционально: 'timeout' в секундах (по умолчанию 90) - применяется к HTTP-вызову SDK к Crawlbase, а не к восходящему краулингу.
.get(url, options=None)
метод
Отправляет GET. options — это dict, сопоставляющий любой параметр Crawling API с его значением. Возвращает dict ответа.
.post(url, data, options=None)
метод
Отправляет POST. data - это тело: передайте dict для form-encoded, строку для сырых данных. options работает так же, как у .get.

Структура ответа (dict, все ключи присутствуют, даже если их значение пустое):

status_code
int
HTTP-статус запроса SDK к Crawlbase. 200 означает, что запрос принят; для результата по целевому сайту проверяйте pc_status.
pc_status
int
Вердикт Crawlbase по целевому сайту. Используйте для решений о повторных попытках.
original_status
int
HTTP-статус, который целевой сайт вернул Crawlbase.
url
str
Итоговый URL после редиректов на стороне целевого сайта.
body
bytes | str
Содержимое страницы (или JSON-строка, если использовался format=json / scraper=).
headers
dict
Заголовки ответа от целевого сайта.
rid
str
Request ID (когда async=true или store=true).