Когда вы парсите несколько сотен страниц, синхронный цикл вполне подходит: отправить запрос, дождаться HTML, разобрать его и повторить. Но эта модель перестаёт работать, когда нужно обработать тысячи или миллионы страниц: каждый запрос блокирует код, пока удалённый браузер рендерит страницу и прокси перебирает повторные попытки. Crawlbase Crawler создан именно для того, чтобы устранить это ожидание. Вы отправляете ему URL, он ставит их в очередь и обходит в фоновом режиме, а каждый готовый результат доставляет на указанный вами вебхук.
В этом руководстве показано, как использовать Crawler от начала до конца на Python: поднять конечную точку вебхука для приёма результатов, создать Crawler с указанием на неё, отправить пакет URL через Crawling API и читать возвращаемый HTML по мере его поступления. По ходу работы вы увидите возможности, делающие Crawler пригодным для масштабирования: асинхронная обработка, обычные и JavaScript-запросы, оплата только за успешные запросы и автоматические повторные попытки. Примеры целевых страниц представляют собой нейтральные общедоступные адреса, а в конце есть краткая заметка об ответственном парсинге.
Что вы построите
Небольшой, но полноценный асинхронный конвейер. С одной стороны, сервер вебхука, принимающий POST-коллбэки от Crawler и сохраняющий каждый результат. С другой, скрипт отправки, передающий URL в именованный Crawler через Crawling API. В итоге у вас будут следующие компоненты:
- Приёмник вебхука. Конечная точка Flask, принимающая POST-коллбэк от Crawler, распаковывающая тело в формате gzip и сохраняющая спарсенный HTML на диск.
- Определение Crawler. Именованный Crawler в вашем дашборде: либо обычный (TCP) Crawler для статических страниц, либо JavaScript Crawler для страниц с клиентским рендерингом, с указанием на URL вашего вебхука.
-
Скрипт отправки. Python-скрипт, отправляющий список URL в Crawler с параметрами
callback=trueиcrawler=YourCrawlerNameи выводящий идентификатор запроса (RID) для каждого из них. - Обработка результатов. Поля, поступающие с каждым коллбэком: RID, исходный URL, коды статуса и тело страницы.
Чем асинхронный Crawler отличается от прямого запроса
Прямой вызов Crawling API синхронен: вы вызываете api.get(url), ваш код блокируется до получения страницы и возвращает HTML в том же ответе. Это правильный инструмент для небольшого количества страниц или для интерактивной работы, когда результат нужен немедленно.
Crawler инвертирует этот поток. Вы отправляете URL, мгновенно получаете короткий идентификатор запроса и продолжаете отправлять остальной пакет. Crawler обходит каждую страницу в фоновом режиме, самостоятельно управляя рендерингом, ротацией IP и повторными попытками, и публикует готовый результат на ваш вебхук, когда он готов. Ваш код никогда не держит соединение открытым на время обхода. Именно это разделение позволяет одному пакету охватить тысячи URL, не заставляя ваш процесс простаивать, и именно поэтому страница продукта async рекомендует его для больших задач. Компромисс: для приёма коллбэков вам нужна публично доступная конечная точка, и именно её вы строите в первую очередь.
При создании Crawler вы выбираете тип. Обычный (TCP) Crawler загружает статический HTML и является более дешёвым вариантом для страниц с серверным рендерингом. JavaScript Crawler сначала рендерит страницу в настоящем браузере, что необходимо, когда контент формируется на стороне клиента (React, Angular или любое другое решение, которое заполняет страницу после загрузки). Выбирайте тип в соответствии с вашей целевой страницей: JavaScript-запросы стоят больше кредитов, чем обычные.
Предварительные требования
Несколько вещей, которые нужно подготовить заранее. Ни одна из них не займёт много времени.
Базовые знания Python. Вы должны уметь запускать скрипты и устанавливать пакеты с помощью pip. Если вы новичок в работе с HTML после его получения, руководство по BeautifulSoup хорошо дополняет это руководство.
Python 3.8 или выше. Проверьте версию командой python --version. Если Python не установлен, скачайте его с python.org и убедитесь, что он добавлен в PATH.
Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте дашборд и скопируйте токен со страницы документации аккаунта. Вы получите обычный токен и JavaScript-токен; используйте тот, что соответствует типу создаваемого Crawler. Crawlbase предоставляет 1 000 бесплатных запросов для начала, чего достаточно, чтобы пройти это руководство. Относитесь к токену как к паролю и не храните его в системе контроля версий.
Способ открыть локальный хост извне. Crawler доставляет результаты через публичный интернет, поэтому ваш вебхук должен быть доступен снаружи вашей машины. Для локальной разработки инструмент туннелирования, например ngrok, перенаправляет публичный URL на ваш локальный порт. В продакшне конечную точку нужно размещать на настоящем сервере.
Настройка проекта
Создайте виртуальное окружение, чтобы зависимости оставались изолированными, а затем установите две нужные вам библиотеки: Flask для сервера вебхука и официальный клиент Crawlbase для скрипта отправки.
python --version python -m venv crawler_env source crawler_env/bin/activate pip install crawlbase flask
В Windows активируйте окружение командой crawler_env\Scripts\activate вместо строки source. Пакет crawlbase является официальным клиентом для отправки URL через Crawling API, а flask даёт вам минималистичный веб-сервер для конечной точки коллбэка. Модуль gzip, используемый для распаковки тела коллбэка, входит в стандартную библиотеку, поэтому больше ничего устанавливать не нужно.
Шаг 1: создание приёмника вебхука
Crawler доставляет каждый результат как POST-запрос на ваш URL коллбэка. Чтобы быть корректной конечной точкой, ваш вебхук должен делать три вещи: быть доступным из публичного интернета, принимать POST-запросы и быстро отвечать со статусом 200, 201 или 204 без тела. Crawler отправляет тело страницы в сжатом виде (gzip), поэтому вы распаковываете его перед сохранением. Вот полный приёмник на Flask.
# webhook.py import gzip from flask import Flask, request, Response app = Flask(__name__) @app.route("/webhook/crawlbase", methods=["POST"]) def webhook(): rid = request.headers.get("rid") url = request.headers.get("url") cb_status = request.headers.get("cb_status") try: body = gzip.decompress(request.data).decode("latin1") except OSError: body = request.data.decode("latin1", errors="replace") with open(f"result_{rid}.html", "w", encoding="latin1") as f: f.write(body) print(f"Received {rid} for {url} (status {cb_status})") return Response(status=204) if __name__ == "__main__": app.run(port=8000)
Конечная точка читает RID, спарсенный URL и статус Crawlbase из заголовков запроса, распаковывает gzip-тело в HTML и записывает его в файл, названный по RID, чтобы каждый результат попадал отдельно. Она возвращает 204 No Content, именно то, что нужно Crawler: быстрое пустое подтверждение. Запустите его командой python webhook.py, и сервер начнёт слушать порт 8000.
Теперь сделайте его публичным. Пока сервер работает, запустите туннель на том же порту:
ngrok http 8000
ngrok выведет публичный URL перенаправления, например https://abc123.ngrok-free.app. Полный URL коллбэка, это хост плюс маршрут, например https://abc123.ngrok-free.app/webhook/crawlbase. Держите его под рукой: он понадобится на следующем шаге. На бесплатном тарифе ngrok URL меняется при каждом перезапуске, поэтому после любого перезапуска считывайте его заново.
Вебхук, который вы только что создали, должен лишь принимать готовый HTML, потому что сложная часть происходит выше по цепочке: когда Crawler обходит каждый переданный URL, Crawling API рендерит страницу там, где это нужно, и ротирует жилые IP на стороне сервера, поэтому вам не нужно самостоятельно запускать флот headless-браузеров или пул прокси. Укажите Crawler на эту конечную точку и отправьте первый пакет на бесплатном тарифе.
Шаг 2: создание Crawler
Имея публичный URL коллбэка, создайте Crawler из дашборда. Откройте раздел Crawler и выберите Create new Crawler. Вам нужно указать три вещи:
-
Имя. Уникальный идентификатор, который вы будете указывать при отправке URL, например
test-crawler. - Тип. Обычный (TCP) для статических страниц или JavaScript для страниц с клиентским рендерингом, как описано выше.
-
URL коллбэка. Публичный URL вебхука из шага 1, включая маршрут:
https://abc123.ngrok-free.app/webhook/crawlbase.
Если вы не хотите запускать собственную конечную точку, Crawlbase Cloud Storage может выступать в роли цели коллбэка и хранить результаты для последующего получения. В этом руководстве мы используем созданный вами вебхук, поскольку он демонстрирует полный поток коллбэков. После сохранения Crawler готов принимать отправленные URL.
Шаг 3: отправка URL в Crawler
Именно здесь в игру вступает Crawling API. Вы вызываете его так же, как и для синхронного обхода, но добавляете две опции: callback=true, чтобы указать, что это асинхронный запрос, и crawler=test-crawler, чтобы назвать Crawler, который должен его обработать. Каждая отправка возвращает идентификатор запроса, а не саму страницу. Вот скрипт отправки.
# push.py from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) urls = [ "https://httpbin.org/html", "https://example.com/", "https://books.toscrape.com/", ] OPTIONS = {"callback": "true", "crawler": "test-crawler"} for url in urls: response = api.get(url, OPTIONS) print(response["body"])
Каждый вызов немедленно возвращает небольшое JSON-тело с RID, а Crawler ставит URL в очередь для фонового обхода. По умолчанию вы можете отправлять до 30 URL в секунду; если вам нужно больше, служба поддержки Crawlbase может поднять этот лимит. Обратите внимание, что обычный токен предназначен для обычного Crawler, а JavaScript-токен, для JavaScript Crawler, поэтому используйте токен, соответствующий созданному типу.
Что возвращает отправка
Запустите python push.py и вы получите по одному RID на каждый URL в том порядке, в котором они были отправлены:
{"rid": "d756c32b0999b1c0507e364f"} {"rid": "455ee207f6907fbd6168ac1e"} {"rid": "e9eb6ce579dec207e8973615"}
RID, это ваш идентификатор каждого запроса. Вы можете использовать его для поиска запроса через управляющие конечные точки Crawler, и он возвращается обратно в коллбэке, чтобы вы могли сопоставить каждый результат с отправленным URL. Поскольку отправка асинхронна, весь пакет возвращается менее чем за секунду; фактический обход происходит после, в фоновом режиме.
Шаг 4: приём результатов на вебхуке
После обхода страницы Crawler отправляет результат POST-запросом на ваш URL коллбэка. Тело, это сжатая в gzip страница, а метаданные передаются в заголовках. По умолчанию ответ представлен в виде HTML, с заголовками следующего вида:
Content-Type: text/plain Content-Encoding: gzip Original-Status: 200 PC-Status: 200 rid: the RID you received in the push call url: the URL which was crawled Body: the gzip-compressed HTML of the page
Original-Status, это статус, который вернул целевой сайт, а PC-Status, собственный статус Crawlbase для данного обхода, поэтому вы можете отличить успешный запрос от неудачного и отреагировать соответствующим образом. Если вы предпочитаете структурированный вывод вместо сырого HTML, передайте format=json при отправке, и тело придёт в виде JSON-объекта:
{ "cb_status": 200, "original_status": 200, "rid": "the RID you received in the push call", "url": "the URL which was crawled", "body": "the HTML of the page" }
Поскольку мы отправили три URL, вебхук получает три POST-запроса, каждый из которых записывает собственный файл result_<rid>.html. Имея HTML на диске, вы можете разбирать его как угодно: именно здесь вы бы загрузили его в BeautifulSoup и извлекли нужные поля, точно так же, как после синхронного обхода.
Если вам нужно передавать собственные идентификаторы через коллбэк, передайте параметр callback_headers при отправке в формате NAME:VALUE|NAME2:VALUE2 (URL-кодированном). Crawler возвращает эти заголовки обратно в результате, поэтому вы можете прикрепить идентификатор задания или ключ записи к каждому URL и считать его из коллбэка без дополнительного поиска.
Ключевые возможности, важные при масштабировании
Описанный выше четырёхэтапный процесс и есть весь паттерн. Его устойчивость на миллионах URL обеспечивается несколькими особенностями Crawler, которые стоит выделить.
- Асинхронная обработка. Отправка мгновенно возвращает RID, а обход выполняется в фоновом режиме, поэтому ваш код никогда не блокируется в ожидании медленной страницы. Один процесс может отправить очень большой пакет и затем просто принимать результаты по мере их поступления.
- Обычные и JavaScript-запросы. Обычный Crawler дёшево загружает статический HTML; JavaScript Crawler рендерит страницу в браузере для контента на стороне клиента. Вы выбираете тип для каждого Crawler, и JavaScript-запросы требуют больше кредитов, чем обычные, поэтому вы платите за рендеринг только тогда, когда он действительно нужен.
- Оплата за успешные запросы. Вы платите за запросы, которые завершились успешно, а не за каждую попытку, что привязывает стоимость крупного обхода к результатам, а не к усилиям.
- Автоматические повторные попытки. Если Crawler доставляет результат на ваш вебхук, но ваш сервер не возвращает успешный статус, он повторяет обход и доставку. Эти повторные попытки засчитываются как успешные запросы после их выполнения, поэтому держите конечную точку быстрой и возвращающей 204.
Одна операционная деталь: если ваш вебхук уходит в офлайн, мониторинг Crawlbase обнаруживает это, приостанавливает Crawler и возобновляет работу, когда конечная точка снова доступна. Общий размер очередей ожидания у ваших Crawler ограничен; если вы достигнете потолка, отправка приостановится с уведомлением по электронной почте и возобновится по мере очистки очереди. Вы редко сталкиваетесь с этим напрямую, но именно поэтому долго выполняющееся асинхронное задание не теряет результаты незаметно.
Масштабирование конвейера
В продакшн-запуске форма остаётся прежней; вы меняете входные данные и принимающую сторону. Несколько привычек помогают поддерживать большие задания в порядке:
- Пакетируйте отправки. Читайте URL из файла или очереди и отправляйте их в цикле, оставаясь в рамках лимита 30 в секунду, если вы не запросили более высокий предел. Сохраняйте каждый возвращённый RID, чтобы позже сверить результаты.
- Делайте вебхук надёжным. Быстро подтверждайте запросы кодом 204, а обработку тела выполняйте асинхронно (запись в хранилище или передача в очередь воркеров), а не внутри запроса. Медленный вебхук вызывает повторные попытки, за которые вы платите.
-
Следите за кодами статуса. Отслеживайте
PC-StatusиOriginal-Statusдля каждого коллбэка, чтобы отличить реальные ошибки страниц от временных, и возвращайте в очередь те, что нуждаются в повторной обработке.
Если вы вообще не хотите управлять хранилищем коллбэков, укажите Crawler на Crawlbase Cloud Storage и получайте результаты по собственному расписанию. Более подробное рассмотрение развёртывания сервиса коллбэков и сохранения результатов см. в статье извлечение данных с помощью Crawlbase Crawler и руководстве по созданию масштабируемого конвейера веб-данных. Если ваши цели активно используют клиентский рендеринг, пошаговое руководство по обходу JavaScript-сайтов подробнее освещает сторону рендеринга.
Ответственный парсинг
Crawler делает масштабный сбор данных простым, что превращает ответственное использование в вопрос дисциплины, а не возможностей. Собирайте только публичные данные, страницы, доступные любому без аккаунта, и не трогайте ничего, что находится за логином или платным доступом. Проверяйте условия использования каждого целевого сайта и его robots.txt и воспринимайте оба документа как границы того, что вы собираете.
Держите темп запросов в разумных пределах. Асинхронная модель позволяет работать интенсивно, поэтому устанавливайте объёмы, не создающие нагрузки на посещаемые сайты. Когда собираемые данные включают что-либо, связанное с идентифицируемыми лицами, обращайтесь с ними как с персональными данными в соответствии с такими нормативными актами, как GDPR и CCPA: минимизируйте хранимое, агрегируйте там, где это возможно, и не стройте профили людей. Нейтральные примеры URL в этом руководстве (httpbin, example.com и учебный книжный магазин) существуют именно для того, чтобы вы могли тестировать поток, не направляя его на чей-то продакшн-сайт.
Ключевые выводы
- Crawler асинхронен по своей природе. Вы отправляете URL, мгновенно получаете RID и принимаете готовые результаты на вебхуке, поэтому ваш код никогда не блокируется на медленном обходе.
-
Вы строите две стороны. Публичную конечную точку вебхука, принимающую POST-коллбэки и возвращающую 204, и скрипт отправки, передающий URL через Crawling API с параметрами
callback=trueиcrawler=YourCrawlerName. - Выбирайте тип Crawler под каждую цель. Обычный (TCP) Crawler для статических страниц, JavaScript Crawler для страниц с клиентским рендерингом; JavaScript-запросы стоят больше кредитов, поэтому вы платите за рендеринг только тогда, когда он нужен.
- Неудачные доставки повторяются автоматически. Если ваш вебхук не отвечает статусом успеха, Crawler повторяет доставку, и эти попытки засчитываются как успешные запросы, поэтому держите конечную точку быстрой.
- Работайте только с публичными данными. Уважайте условия использования и robots.txt каждого сайта, держите темп разумным и обращайтесь с персональными данными в соответствии с GDPR и CCPA.
Часто задаваемые вопросы
Чем Crawler отличается от обычного вызова Crawling API?
Обычный вызов Crawling API синхронен: вы ждёте ответа и получаете HTML в том же запросе. Crawler асинхронен: вы отправляете URL, мгновенно получаете идентификатор запроса, а готовый результат публикуется на вашем вебхуке позже. Используйте прямой вызов для нескольких страниц или интерактивной работы, а Crawler, когда нужно обработать тысячи или миллионы URL, не блокируя код.
Что должен делать мой вебхук, чтобы быть корректным?
Он должен быть доступен из публичного интернета, принимать POST-запросы и быстро отвечать статусом 200, 201 или 204 без тела. Crawler отправляет страницу в сжатом виде gzip, поэтому распаковывайте тело перед использованием. Подтверждайте быстро и выполняйте более тяжёлую обработку после, потому что медленный вебхук может вызвать повторные попытки.
Обязательно ли использовать Python?
Нет. Python удобен здесь благодаря официальному клиенту Crawlbase и Flask, но Crawler не зависит от языка. Сторона отправки, это вызов Crawling API с параметрами callback=true и crawler=YourCrawlerName, а вебхук, любая HTTP-конечная точка, принимающая POST-запросы. Вы можете реализовать обе стороны на JavaScript, Ruby, Go или любом другом языке, умеющем работать с HTTP.
Что такое RID и как его использовать?
RID (идентификатор запроса) возвращается при отправке URL и возвращается обратно в коллбэке. Он позволяет сопоставить каждый входящий результат с отправленным URL, а также использовать его для поиска запроса через управляющие конечные точки Crawler. Хранение RID для каждой отправки, простейший способ сверить большой пакет по мере поступления результатов.
Когда следует использовать JavaScript Crawler вместо обычного?
Используйте JavaScript Crawler, когда нужный контент рендерится на стороне клиента: например, приложение на React или Angular либо страница, которая заполняется после загрузки. Обычный (TCP) Crawler достаточен для серверного статического HTML и стоит меньше кредитов за запрос. Соотносите тип Crawler с вашей целью и используйте соответствующий токен (обычный или JavaScript).
Как работает тарификация при повторных попытках?
Вы платите только за успешные запросы, а не за каждую попытку, при этом JavaScript-запросы требуют больше кредитов, чем обычные. Если Crawler пытается доставить результат, но ваш вебхук не возвращает статус успеха, он повторяет попытку и доставку; эти повторные попытки засчитываются как успешные запросы после их выполнения. Быстрая работа конечной точки с возвратом 204 позволяет избежать оплаты за ненужные повторные попытки.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
