Python
Официальный Python-клиент для платформы Crawlbase. Один пакет оборачивает все API - Crawling, Scraper, Smart AI Proxy, Storage, Crawler, Screenshots - с идиоматичной для Python эргономикой параметров, ошибок и повторов.
Как устроен 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-методы.
'timeout' в секундах (по умолчанию 90) - применяется к HTTP-вызову SDK к Crawlbase, а не к восходящему краулингу.options — это dict, сопоставляющий любой параметр Crawling API с его значением. Возвращает dict ответа.data - это тело: передайте dict для form-encoded, строку для сырых данных. options работает так же, как у .get.Структура ответа (dict, все ключи присутствуют, даже если их значение пустое):
200 означает, что запрос принят; для результата по целевому сайту проверяйте pc_status.format=json / scraper=).async=true или store=true).