Войти

Как устроен SDK

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

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

  • URL-кодирование, валидация параметров и разбор ответов работают из коробки - код читается как продуктовый код, а не как HTTP-обвязка.
  • Поддерживаются и ESM (import { CrawlingAPI } from 'crawlbase'), и CommonJS (const { CrawlingAPI } = require('crawlbase')).
  • Один клиентский класс на каждый Crawlbase API, все с одинаковой формой конструктора и вызовов.
  • Разумные значения по умолчанию (90-секундный таймаут, автоматический парсинг JSON для ответов format=json, декодирование UTF-8) — то, что большинство команд настраивают вручную при первой интеграции.

SDK имеет открытый исходный код, лицензию MIT и принимает PR от сообщества на github.com/crawlbase/crawlbase-node.

Установка

Последняя версия в npm. Работает с Node.js 16+ во всех основных пакетных менеджерах.

npm install crawlbase

# Or via pnpm / yarn / bun
pnpm add crawlbase
yarn add crawlbase
bun add crawlbase

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

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

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

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

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

import { CrawlingAPI } from 'crawlbase';

// Pick the right token at instantiation; the SDK doesn't switch
// tokens per-call, so keep two clients if you alternate.
const api = new CrawlingAPI({ token: process.env.CRAWLBASE_TOKEN });
const js  = new CrawlingAPI({ token: process.env.CRAWLBASE_JS_TOKEN });

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

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

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

Три строки от импорта до получения HTML. Работают и ESM, и CommonJS:

// ESM
import { CrawlingAPI } from 'crawlbase';

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

if (res.statusCode === 200) {
  console.log(res.body);
}

// CommonJS - same shape
// const { CrawlingAPI } = require('crawlbase');

Ветвите по response.statusCode (HTTP-статус SDK к Crawlbase) и response.headers.pc_status (вердикт Crawlbase - см. Ошибки ниже), принимая решение о повторной попытке. Передайте { format: 'json' }, чтобы получить JSON-конверт вместо сырого содержимого страницы.

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

У каждого Crawlbase API есть соответствующий клиентский класс. Тот же конструктор, те же глаголы get / post.

import {
  CrawlingAPI,    // general-purpose page fetch
  ScraperAPI,     // parsed JSON for supported sites
  LeadsAPI,       // domain-scoped email extraction (legacy)
  ScreenshotsAPI, // screenshots of any URL
} from 'crawlbase';

const token = { token: 'YOUR_TOKEN' };

const crawl   = new CrawlingAPI(token);
const scraper = new ScraperAPI(token);
const leads   = new LeadsAPI(token);
const shots   = new ScreenshotsAPI(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, затем скролл для ленивой подгрузки, затем клик по любому блокирующему UI-элементу.

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

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

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

import { ScraperAPI } from 'crawlbase';

const api = new ScraperAPI({ token: 'YOUR_TOKEN' });
const res = await api.get(
  'https://www.amazon.com/dp/1098145356',
  { scraper: 'amazon-product-details' }
);
const data = JSON.parse(res.body);
console.log(data.name, data.price);

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

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

const api = new CrawlingAPI({ token: 'YOUR_TOKEN' });

// Hit the German Amazon catalog from a German residential IP
const res = await api.get(
  'https://www.amazon.com/dp/1098145356',
  { country: 'DE' }
);

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

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

const api = new CrawlingAPI({ token: 'YOUR_TOKEN' });
const sleep = ms => new Promise(r => setTimeout(r, ms));

async function crawl(url, attempts = 5) {
  for (let i = 0; i < attempts; i++) {
    const res = await api.get(url);
    if (res.statusCode === 200 && Number(res.headers.pc_status) === 200) {
      return res;
    }
    if (res.statusCode >= 400 && res.statusCode < 500) {
      throw new Error(`client error ${res.statusCode}: ${url}`);
    }
    await sleep(Math.random() * (2 ** i) * 1000);
  }
  throw new Error(`Failed: ${url}`);
}

Асинхронные краулы и вебхуки

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

const api = new CrawlingAPI({ token: 'YOUR_TOKEN' });
const res = await api.get('https://example.com', {
  async: true,
  callback: 'https://your-app.com/webhook',
});
const rid = res.rid;  // correlate the eventual webhook delivery

// Your Express / Fastify / Hono webhook receives a POST with:
//   { rid, url, original_status, pc_status, body }

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

Sticky-сессии

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

const api = new CrawlingAPI({ token: 'YOUR_JS_TOKEN' });

const session = `checkout-${userId}`;
await api.get('https://shop.example.com/cart',     { cookies_session: session });
await api.get('https://shop.example.com/checkout', { cookies_session: session });
await api.get('https://shop.example.com/confirm',  { cookies_session: session });

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

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

const res = await api.get(url);
const pc = Number(res.headers.pc_status);

if (pc === 200) {
  use(res.body);
} else if (pc === 520 || pc === 525) {
  // 520 = empty body, 525 = anti-bot couldn't be solved.
  // Switch to JS token and retry.
  await retryWithJsToken(url);
} else if ([521, 522, 523].includes(pc)) {
  // Target unreachable or timed out. Retry with backoff.
  schedule_retry(url);
} else {
  logger.error('crawl failed', { url, pc_status: pc });
}

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

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

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

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

У всех клиентских классов одна и та же поверхность. Конструктор принимает единственный объект опций; глаголы зеркалят соответствующие HTTP-методы. Каждый метод возвращает Promise.

new CrawlingAPI({ token, timeout })
constructor
Инициализирует клиент с вашим токеном. Опционально: timeout в миллисекундах (по умолчанию 90000).
.get(url, options?)
method
Отправляет GET. options сопоставляет любой параметр Crawling API с его значением.
.post(url, data, options?)
method
Отправляет POST. data - это body: передайте объект для form-encoded, строку для raw.

Форма ответа (объект, все свойства присутствуют, даже если пустые):

response.statusCode
number
HTTP-статус запроса SDK к Crawlbase.
response.body
string
Содержимое страницы (или JSON-строка, когда использовался format=json / scraper=). По умолчанию декодируется в UTF-8.
response.url
string
Финальный URL после редиректов на стороне целевого сайта.
response.headers
object
Заголовки ответа в нижнем регистре. Специфичные для Crawlbase поля статуса доступны здесь:
  • response.headers.pc_status - вердикт Crawlbase по целевому ресурсу (ветвите по нему для решений о повторной попытке).
  • response.headers.original_status - HTTP-статус, который целевой сайт вернул Crawlbase.
  • response.headers.rid - Request ID (когда вызов содержал async: true или store: true).
response.json
object | undefined
Заранее распарсенный JSON, когда Content-Type ответа — JSON. SDK парсит его один раз, чтобы вам не пришлось.