Веб-краулинг перестаёт быть задачей скрейпинга задолго до того, как становится задачей парсинга. Сложность не в загрузке HTML и не в извлечении данных. Она в координации миллионов загрузок по тысячам доменов так, чтобы не терять работу, не краулить одну и ту же страницу дважды и не тратить время на поддержку пулов прокси и браузерной инфраструктуры вместо разработки собственного приложения.

Именно здесь меняется архитектура. Продакшен-краулеру нужны очереди, воркеры, повторные попытки, ротация прокси, рендеринг JavaScript, обход антибот-защиты и надёжный фронтир краулинга, способный непрерывно расширяться, не возвращаясь к уже посещённым URL. Иными словами, вы решаете задачу распределённых систем.

Более удачный подход: отделить оркестрацию краулинга от его выполнения. Ваше приложение решает, что краулить, насколько глубоко и что извлекать. Инфраструктура краулинга берёт на себя очереди, конкурентность, повторные попытки, рендеринг и надёжность сети, оставляя вашему движку бизнес-логику вместо инфраструктуры.

В этой статье мы построим распределённый движок краулинга на Node.js, следующий именно этой схеме. Движок отвечает за политику краулинга, дедупликацию URL, парсинг HTML, хранение результатов и рекурсивное расширение фронтира, а Crawlbase предоставляет распределённый слой выполнения через Crawlbase Enterprise Crawler и Crawlbase Crawling API. Enterprise Crawler работает как управляемая очередь с парком воркеров, асинхронно доставляющая результаты краулинга на вебхук, а Crawling API даёт синхронный путь загрузки для запросов, чувствительных к задержке. В итоге получается краулер, который масштабируется вместе с инфраструктурой Crawlbase и при этом остаётся достаточно компактным, чтобы понять его за несколько сотен строк кода.

Каждый фрагмент реализации в этой статье взят из сопутствующего репозитория на GitHub. Склонируйте его, проходите каждый этап реализации параллельно со статьёй, и вы получите готовую к продакшену основу, которую сможете расширить собственной логикой извлечения, хранилищем и политиками краулинга.

Проектирование распределённого краулера

Каждый распределённый краулер непрерывно решает четыре задачи:

  1. Управление фронтиром краулинга: решать, что краулить дальше.
  2. Выполнение краулинга: надёжно загружать страницы в больших масштабах.
  3. Обработка результатов: извлекать и сохранять полезные данные.
  4. Расширение обхода: превращать только что найденные ссылки в будущие задания краулинга.

Эти обязанности тесно связаны. Каждый завершённый краул даёт и данные, и новые URL. Эти URL проходят через политику краулинга, попадают во фронтир и в конце концов тоже загружаются, образуя непрерывную петлю обратной связи.

Фронтир краулинга

Фронтир служит памятью краулера о предстоящей работе. Каждый найденный URL нормализуется, проверяется по политике краулинга, дедуплицируется и планируется на краулинг. Без управляемого фронтира рекурсивные обходы быстро начинают повторно посещать одни и те же страницы или выходить за пределы заданной области.

Выполнение краулинга

Загрузка страниц в больших масштабах по большей части является инфраструктурной задачей. Она требует координации воркеров, повторных попыток, ротации прокси, браузерного рендеринга и обхода антибот-защиты ещё до того, как ваш парсер увидит HTML. Построить и эксплуатировать такую инфраструктуру зачастую сложнее, чем сам краулер.

Обработка результатов

Завершённые краулы должны поступать в независимый конвейер обработки, где страницы парсятся, извлекаются структурированные данные и сохраняются результаты. Разделение получения страниц и их обработки упрощает сопровождение и развитие обеих систем.

Рекурсивное расширение

Каждая обработанная страница порождает новые ссылки. Пройдя проверки глубины, домена и дедупликации, эти ссылки становятся новыми заданиями краулинга и снова попадают во фронтир. Эта рекурсивная петля обратной связи продолжается, пока в заданной области не останется непосещённых страниц.

Движок, который мы строим, отвечает за фронтир, политику краулинга, парсинг, хранение и рекурсивное расширение. Crawlbase предоставляет распределённую очередь, парк воркеров, повторные попытки, браузерный рендеринг, ротацию прокси и антибот-инфраструктуру. Такое разделение позволяет движку сосредоточиться на логике приложения, а не на инфраструктуре краулинга.

Что мы строим

Небольшой сервис на Express и набор скриптов, которые вместе образуют самоподдерживающийся краулер:

  • Одноразовый скрипт настройки создаёт именованную очередь Crawler, привязанную к вашему вебхуку.
  • Сид-скрипт отправляет стартовые URL в очередь.
  • Crawlbase краулит каждый URL и отправляет результат POST-запросом на ваш вебхук.
  • Вебхук парсит страницу, сохраняет запись, находит ссылки и возвращает в очередь те из них, что входят в область обхода и ещё не встречались.

В результате получается краулер, масштабирующийся за счёт конкурентности Crawlbase, а не ресурсов вашего сервера, и устроенный так, что его можно осмыслить за несколько сотен строк кода.

Обзор архитектуры

Краулинг устроен как цикл, а не как конвейер. Сид-URL заполняют очередь, Crawlbase выполняет каждый краул за ротационными прокси, результаты приходят на вебхук, и каждая ссылка в области обхода, прошедшая проверки фронтира, возвращается в очередь, пока не останется ничего нового.

Поток данных образует цикл. Сид-скрипт запускает движок, который отправляет URL в Enterprise Crawler. Crawler и есть распределённая часть: он держит очередь, выполняет краулы с настроенной конкурентностью через прокси-сеть Crawlbase и берёт на себя повторные попытки и обход антибот-защиты на целевых сайтах. Когда краул завершается, Crawlbase отправляет страницу POST-запросом обратно на вебхук движка. Парсер движка формирует запись для хранилища и список исходящих ссылок, которые через дедупликацию и проверку глубины возвращаются в следующий раунд отправки.

Crawlbase отвечает за загрузку страниц, конкурентность, повторные попытки и инфраструктуру прокси и антибот-защиты. Движок отвечает за политику краулинга (что входит в область обхода, насколько глубоко идти) и за то, что делать с данными. На главной диаграмме выше видно и пунктирное ребро: Crawling API, используемый синхронно для разовых загрузок отдельных страниц, когда результат нужен сразу, а не через очередь.

Подготовка проекта

Теперь, когда архитектура определена, запустим проект локально. Сопутствующий репозиторий содержит полную реализацию, используемую в этой статье. Мы будем работать с проектом в final/, сверяясь с промежуточными контрольными точками в steps/ по мере сборки каждого компонента.

Вам понадобятся:

  • Node.js 18 или новее (скрипт настройки использует встроенный fetch).
  • Аккаунт Crawlbase, чтобы получить токены запросов.
  • Публично доступная точка вебхука. Для локальной разработки откройте доступ к вашему серверу Express через Cloudflare Tunnel (cloudflared) или ngrok, затем укажите в CALLBACK_URL адрес https://<your-public-host>/webhook.

Склонируйте репозиторий и установите проект из каталога final/:

bash
git clone https://github.com/ScraperHub/building-a-distributed-crawling-engine.git
cd building-a-distributed-crawling-engine/final
npm install
cp .env.example .env

Затем впишите в .env ваш токен Crawlbase и публичный URL обратного вызова. Далее в статье каждый шаг реализации напрямую соответствует контрольной точке в steps/, а в final/ всегда лежит полный работоспособный проект. В файле README репозитория приведено сопоставление каждого раздела статьи с кодом.

Шаг 1: централизуем конфигурацию

Движок начинается с единого источника истины для конфигурации. Вместо того чтобы разбрасывать секреты и значения политики краулинга по кодовой базе, всё загружается из переменных окружения и валидируется при запуске. Если обязательное значение, например токен Crawlbase, отсутствует, движок падает сразу, а не позже, посреди краула.

Полная реализация находится в final/src/config.js в сопутствующем репозитории.

js
const config = {
  crawlbaseToken: required('CRAWLBASE_TOKEN'),
  crawlerName: process.env.CRAWLER_NAME || 'distributed-engine',
  callbackUrl: process.env.CALLBACK_URL || '',
  port: Number(process.env.PORT || 3000),
  maxDepth: Number(process.env.MAX_DEPTH || 2),
  allowedDomains: (process.env.ALLOWED_DOMAINS || '')
    .split(',')
    .map((domain) => domain.trim().toLowerCase())
    .filter(Boolean),
};

Большинство этих значений задают политику краулинга движка, а не его инфраструктуру. MAX_DEPTH ограничивает глубину рекурсивного расширения, а ALLOWED_DOMAINS удерживает обход в пределах сайтов, которые вы явно разрешили. Один и тот же CRAWLBASE_TOKEN аутентифицирует и Enterprise Crawler, и Crawling API, так что для связи с Crawlbase движку достаточно одних учётных данных.

Когда конфигурация готова, следующим шагом создаём распределённый краулер, который будет выполнять наши задания.

Шаг 2: создаём распределённую очередь

В Crawlbase распределённой очередью служит Enterprise Crawler: управляемая очередь и парк воркеров, которые принимают URL, асинхронно их краулят и доставляют результаты либо на вебхук, либо в Cloud Storage. Мы будем использовать доставку на вебхук, указав callback_url при создании краулера.

Логика настройки реализована в final/src/setup-crawler.js. Management API ожидает токен Crawlbase в пути URL, а не в строке запроса, поэтому скрипт формирует эндпоинт соответствующим образом.

js
const endpoint = `https://api.crawlbase.com/crawler/${config.crawlbaseToken}`;
const response = await fetch(endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: config.crawlerName,
    callback_url: config.callbackUrl,
  }),
});

Создайте краулер один раз:

bash
npm run setup

Когда краулер привязан к вашему вебхуку, добавление работы в очередь превращается в обычный запрос к Crawling API с двумя дополнительными параметрами. crawler указывает целевую очередь, а callback=true говорит Crawlbase обработать запрос асинхронно, не возвращая страницу сразу. Запрос возвращает идентификатор запроса (rid), как только URL принят в очередь, а сам краул выполняется в фоне.

Логика отправки реализована в final/src/crawlbase-client.js.

js
async function pushToCrawler(url, depth) {
  const response = await api.get(url, {
    crawler: config.crawlerName,
    callback: true,
    callbackHeaders: `X-Crawl-Depth|${depth}`,
  });

  // Surface auth/quota errors instead of silently dropping the URL.
  if (response.statusCode !== 200) {
    throw new Error(`Crawler push failed (${response.statusCode}): ${response.body}`);
  }

  // The push response is the small JSON envelope { "rid": "..." }, but it is
  // not served with a JSON content-type, so parse the body ourselves.
  const parsed = response.json || parseRid(response.body);
  return parsed && parsed.rid;
}

Здесь стоит отметить две детали реализации. Во-первых, хотя ответ на отправку содержит JSON, он возвращается без JSON-типа содержимого, поэтому хелпер разбирает тело ответа сам, а не полагается на автоматическую десериализацию. Во-вторых, callbackHeaders позволяет движку не хранить состояние. Текущая глубина краула прикрепляется к запросу как X-Crawl-Depth, и Crawlbase возвращает этот заголовок при доставке вебхука. Так движок восстанавливает глубину краула, не ведя собственного учёта запросов.

Тем же хелпером пользуется сид-скрипт, реализованный в final/src/seed.js, чтобы поставить в очередь начальный набор URL.

js
for (const url of SEED_URLS) {
  if (!shouldCrawl(url, 0)) {
    console.log(`Skipped (filtered or duplicate): ${url}`);
    continue;
  }
  const rid = await pushToCrawler(url, 0);
  console.log(`Queued ${url} -> rid ${rid}`);
}

Запуск npm run seed печатает строку Queued <url> -> rid <rid> для каждого принятого сид-URL. С этого момента распределённый краулер работает. URL уже лежат в очереди Crawlbase, и первые результаты краулинга начнут приходить на вебхук, который мы реализуем дальше.

Шаг 3: обрабатываем результаты краулинга вебхуком

Как только краулер начинает обрабатывать URL, движку нужен способ получать результаты. Каждый завершённый краул доставляется на настроенный ранее callback_url. HTML-страница приходит в теле запроса, а метаданные, такие как pc_status, original_status, rid, url и любые пользовательские заголовки обратного вызова, передаются как HTTP-заголовки.

Сначала подтверждение, работа потом. Crawlbase ожидает пустой ответ 2xx примерно за 200 мс, поэтому вебхук немедленно завершает ответ и откладывает парсинг, сохранение и постановку в очередь в setImmediate; на проверки здоровья от мониторингового бота вебхук отвечает пустым подтверждением.

Реализация вебхука находится в final/src/server.js. Здесь важны две детали. Во-первых, Crawlbase доставляет ответы сжатыми gzip, поэтому сервер использует express.raw(), чтобы получить тело запроса как Buffer, который Express прозрачно распаковывает. Во-вторых, подтверждать вебхук нужно как можно быстрее: подтвердите сразу, обрабатывайте после отправки ответа.

js
app.use(express.raw({ type: '*/*', limit: '10mb' }));

app.post('/webhook', (req, res) => {
  // The monitoring bot probes this endpoint to detect outages. Acknowledge
  // it as a no-op - it carries no real crawl result to process. Crawlbase
  // expects a 2xx with an empty body, so end the response without content.
  if ((req.headers['user-agent'] || '').includes('Crawlbase Monitoring Bot')) {
    return res.status(200).end();
  }

  const pcStatus = Number(req.headers['pc_status']);
  const rid = req.headers['rid'];
  const url = req.headers['url'];
  const depth = Number(req.headers['x-crawl-depth'] || 0);

  const html = req.body.toString('utf8');
  res.status(200).end();

  if (pcStatus !== 200 || !rid || !url) {
    return;
  }

  setImmediate(() => handleResult({ rid, url, depth, html }));
});
Контракт здоровья вебхука

Crawlbase проверяет здоровье вебхука по пустому ответу 2xx, доставленному примерно за 200 миллисекунд, и периодически опрашивает эндпоинт своим мониторинговым ботом. Поэтому обработчик отвечает res.status(200).end() без тела ответа, а запросы бота подтверждаются без какой-либо обработки. Медленные или недоступные эндпоинты вызывают повторные доставки.

Обработчик также смотрит на pc_status, а не на original_status целевого сайта. Значение pc_status, равное 200, означает, что Crawlbase успешно завершил краул, применив все необходимые повторные попытки и обход антибот-защиты, поэтому неудавшиеся запросы движок может просто игнорировать.

Обратите внимание: сама обработка выполняется внутри setImmediate(), уже после подтверждения ответа. Это сохраняет отзывчивость вебхука независимо от объёма последующего парсинга и сохранения и позволяет Crawlbase доставлять новые результаты краулинга, не дожидаясь окончания дальнейшей обработки.

На этом этапе движок получает результаты краулинга, но пока не делает с ними ничего полезного. Следующий шаг: парсить каждую страницу, извлекать структурированные данные, находить новые ссылки и возвращать их краулеру.

Шаг 4: извлекаем данные и расширяем фронтир

Именно здесь краулер становится самоподдерживающимся. Каждая страница, доставленная на вебхук, даёт два результата: структурированную запись, которую можно сохранить, и новый набор ссылок, которые могут стать будущими заданиями краулинга. Фронтир стоит между этими двумя стадиями и следит за тем, чтобы обход оставался ограниченным, детерминированным и свободным от дублирующей работы.

Реализация фронтира находится в final/src/frontier.js.

js
function shouldCrawl(rawUrl, depth) {
  if (depth > config.maxDepth) {
    return false;
  }
  const url = normalize(rawUrl);
  if (!url || !isAllowed(url) || seen.has(url)) {
    return false;
  }
  seen.add(url);
  return true;
}

Хелпер shouldCrawl выступает привратником движка. Каждый найденный URL нормализуется, проверяется по списку разрешённых доменов, сверяется с максимальной глубиной краула и помечается как уже виденный, прежде чем вернуться в обход. Эта единственная функция задаёт область краулера, гарантирует завершение обхода и исключает дублирующую работу.

Когда страница проходит через вебхук, движок извлекает её данные, сохраняет результат и оценивает каждую исходящую ссылку для следующего раунда краулинга. Логика извлечения и сохранения реализована в final/src/extract.js, а оркестрация происходит в обработчике вебхука в final/src/server.js.

js
async function handleResult({ rid, url, depth, html }) {
  const { record, links } = extract(html, url);
  save(rid, { rid, url, depth, crawledAt: new Date().toISOString(), ...record });

  let queued = 0;
  for (const link of links) {
    if (shouldCrawl(link, depth + 1)) {
      try {
        await pushToCrawler(link, depth + 1);
        queued += 1;
      } catch (error) {
        console.error(`Failed to queue ${link}: ${error.message}`);
      }
    }
  }
  console.log(`[${rid}] depth=${depth} url=${url} queued=${queued} new links`);
}

Каждая исходящая ссылка проходит через фронтир, прежде чем стать новым заданием краулинга. Валидные URL сразу отправляются обратно в Enterprise Crawler, а дубликаты, домены вне области обхода и страницы глубже настроенного предела отбрасываются. Движок не ждёт, пока эти страницы будут обойдены: он просто ставит их в очередь и продолжает обрабатывать текущий результат. Распределённое выполнение берёт на себя Crawlbase, и вебхук получает следующую готовую страницу, когда она завершена.

Эта рекурсивная петля обратной связи и есть ядро архитектуры. Каждый завершённый краул порождает новую работу, пока в области обхода не останется неоткрытых URL, что позволяет движку непрерывно расширять обход без собственного пула воркеров и собственной очереди.

Полный жизненный цикл краулинга

К этому моменту все части движка на месте. С запущенным туннелем и CALLBACK_URL, указывающим на него, весь краул стартует всего тремя командами:

bash
npm run setup   # once: create the crawler and bind it to your webhook
npm start       # start the webhook consumer
npm run seed    # enqueue the initial URLs

Дальше движок работает автономно. Сид-URL ставятся в очередь, Crawlbase обрабатывает их асинхронно, готовые страницы доставляются на вебхук, структурированные данные извлекаются и сохраняются, а каждая новая найденная ссылка проходит оценку, прежде чем вернуться в очередь. Цикл повторяется, пока в области обхода не останется страниц для краулинга.

Поскольку движок лишь оркестрирует процесс, пропускную способность определяет конкурентность воркеров Crawlbase, а не ресурсы вашего приложения. Для масштабирования обхода не нужны дополнительные воркер-процессы или изменения самого движка; достаточно позволить Crawlbase обрабатывать больше заданий одновременно. По мере продвижения краула следить за активностью можно по логам сервера и растущей коллекции JSON-записей в каталоге results/.

Архитектура также поддерживает синхронную загрузку страниц, когда постановка в очередь не подходит. Хелпер fetchInline в final/src/crawlbase-client.js использует Crawling API, чтобы немедленно получить одну страницу с тем же токеном Crawlbase. На практике Enterprise Crawler лучше подходит для объёмных асинхронных обходов, а Crawling API для запросов, чувствительных к задержке, например пользовательских запросов или ИИ-агентов, получающих контекст по требованию.

Соображения для продакшена

Реализация, которую мы построили, намеренно компактна, чтобы архитектура оставалась понятной. Прежде чем использовать её в продакшене, стоит укрепить несколько мест.

  • Вынесите фронтир в общее хранилище. Пример хранит множество seen в памяти, а значит, дедупликация ограничена одним процессом и исчезает при перезапуске. Для нескольких экземпляров движка или долгих обходов перенесите фронтир в Redis или другое общее хранилище с ключами по нормализованным URL.
  • Управляйте секретами вне приложения. Пример загружает токен Crawlbase из .env для локальной разработки. В продакшене внедряйте учётные данные через менеджер секретов вашей платформы, а не храните их в конфигурационных файлах.
  • Держите вебхук быстрым и надёжным. Вебхук должен подтверждать запросы немедленно и откладывать тяжёлую обработку до отправки ответа. Медленные или недоступные эндпоинты вызывают повторные доставки, поэтому защита эндпоинта общим секретом или пользовательскими заголовками обратного вызова повышает и надёжность, и безопасность.
  • Рассмотрите Crawlbase Cloud Storage для асинхронной обработки. Вебхуки идеальны, когда результаты краулинга нужно обрабатывать сразу по готовности, но это не единственный способ доставки. Когда Enterprise Crawler настроен на Cloud Storage, каждый завершённый краул автоматически сохраняется без всякого вебхука, а ваше приложение забирает результаты в удобном ему ритме через Storage API. Это хорошо подходит для пакетной обработки, окружений, где открыть HTTPS-эндпоинт непрактично, и процессов, которым полезен постоянный URL для каждой обойдённой страницы. Подробности в документации по режиму доставки Storage.
  • Следите за ростом очереди. Enterprise Crawler применяет лимиты на конкурентность, ёмкость очереди и частоту отправки, чтобы обходы оставались предсказуемыми. Если производители опережают потребителей, отслеживайте размер очереди и приостанавливайте или очищайте разросшиеся обходы через Management API, пока они не потратили лишние ресурсы. С ростом нагрузки можно запросить повышение лимитов конкурентности и частоты отправки через панель поддержки Crawlbase.
  • Выбирайте подходящий режим рендеринга. Начинайте с токена Normal, когда это возможно. Если целевой сайт сильно зависит от клиентского рендеринга или возвращает страницы с проверками, переключитесь на JavaScript Crawler и используйте параметры рендеринга, такие как page_wait или ajax_wait, чтобы дождаться динамического контента перед извлечением.
  • Уважайте границы обхода. Держите краулер в пределах доменов, которыми владеете или к которым имеете разрешённый доступ, соблюдайте robots.txt и условия использования каждого сайта, где это применимо, и настраивайте разумные лимиты краулинга, чтобы не создавать лишний трафик.

Заключение

Мы построили распределённый движок краулинга, разделив оркестрацию краулинга и его выполнение. Движок отвечает за политику краулинга, дедупликацию URL, парсинг, хранение и рекурсивное расширение фронтира, а Crawlbase предоставляет распределённую очередь, парк воркеров, повторные попытки, браузерный рендеринг и прокси-инфраструктуру. Такое разделение делает приложение компактным, понятным и сосредоточенным на логике, которая делает его уникальным.

Пример реализации намеренно ставит простоту выше готовности к продакшену. С ростом нагрузки вы можете заменить фронтир в памяти на Redis, сохранять результаты краулинга в базу данных или запускать несколько экземпляров движка без состояния за одной распределённой очередью, не меняя общую архитектуру.

Crawlbase Enterprise Crawler

Управляемая очередь и парк воркеров для асинхронного краулинга в больших масштабах: отправляйте URL, и готовые страницы приходят на ваш вебхук или в Cloud Storage с уже применёнными повторными попытками, рендерингом JavaScript, ротацией прокси и обходом антибот-защиты. Политика остаётся за вашим движком; загрузку выполняет Crawlbase. Создайте аккаунт и начните с бесплатного тарифа.

Часто задаваемые вопросы

Когда использовать Enterprise Crawler вместо Crawling API?

Эти два сервиса решают разные задачи. Используйте Enterprise Crawler для асинхронных крупномасштабных обходов, где нужны очередь, повторные попытки, конкурентность и доставка на вебхук или в Cloud Storage. Используйте Crawling API, когда страница нужна немедленно, например для запроса от пользователя или контекста для ИИ-агента в реальном времени. Простое правило: очередь для пропускной способности, Crawling API для запросов с низкой задержкой.

Обязательно ли открывать публичный вебхук?

Нет. В этой статье используется вебхук, потому что это самый оперативный способ обрабатывать результаты краулинга по мере готовности. Как вариант, можно настроить Enterprise Crawler на доставку результатов в Crawlbase Cloud Storage и забирать их позже через Storage API. Это часто удобнее для пакетной обработки или окружений, где открыть публичный HTTPS-эндпоинт непрактично.

Когда использовать JavaScript-токен вместо токена Normal?

Начинайте с токена Normal, когда это возможно: он быстрее и экономичнее. Если целевой сайт рендерит контент на клиенте, возвращает пустую HTML-оболочку или показывает антибот-проверки, требующие браузера, переключитесь на JavaScript-запрос и при необходимости используйте параметры рендеринга, такие как page_wait или ajax_wait.

Как заставить краулер обрабатывать URL быстрее?

Сам движок намеренно лёгкий: он лишь оркестрирует обход. Общую пропускную способность определяет конкурентность Enterprise Crawler, а не ресурсы вашего приложения. Если нагрузке нужна пропускная способность выше текущих лимитов, запросите повышение через панель поддержки.

Можно ли запускать несколько экземпляров этого движка?

Да. Архитектура рассчитана на горизонтальное масштабирование. Изменить нужно только фронтир в памяти. Замена локального множества seen на общее хранилище, например Redis, позволяет нескольким потребителям вебхука согласовывать состояние обхода, разделяя одну очередь Enterprise Crawler.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга