Веб-скрапинг всегда состоял из двух склеенных вместе задач: получить страницу, а затем извлечь из неё нужные поля. Вторая задача является источником гниения большинства скраперов. Вы пишете CSS-селекторы или XPath под конкретный макет, сайт выпускает редизайн, и ваше извлечение молча возвращает пустые строки. Большие языковые модели меняют экономику здесь. Вместо того чтобы описывать, где значение находится в DOM, вы описываете, что хотите, на обычном русском и позволяете модели читать контент так, как это делает человек.
В этом руководстве показано, как правильно выполнять веб-скрапинг с Gemini AI на Python: использовать Crawling API для загрузки и рендеринга целевой страницы в чистый HTML или markdown, а затем передавать этот контент Google Gemini для извлечения структурированного JSON. Разделение труда имеет принципиальное значение и составляет суть этой статьи. Crawlbase выполняет загрузку и рендеринг за реальным браузером и доверенным IP; Gemini выполняет чтение и структурирование. Каждый инструмент делает ту часть, в которой действительно хорош.
Зачем вообще объединять Gemini со слоем загрузки
Gemini, это большая языковая модель от Google. Она понимает естественный язык, читает беспорядочный контент и возвращает структурированные данные по запросу. Чего она не делает, так это не загружает веб-страницы. У неё нет HTTP-клиента, нет браузера, нет пула прокси и нет способа обойти антибот-защиту, охраняющую большинство коммерческих сайтов. Передайте ей URL и она не сможет его открыть; передайте ей сырой HTML, который вы сами собрали, и она с удовольствием извлечёт из того, что вам удалось получить, включая пустую оболочку.
Именно этот пробел заполняет слой загрузки. Современные сайты рендерят контент на стороне клиента и агрессивно проверяют автоматизированный трафик, поэтому обычный requests.get нередко возвращает 200 без единого нужного вам данного. Нужен браузер, который действительно запускает JavaScript страницы, и IP-адрес, который сайт воспринимает как реального посетителя. Это можно собрать самостоятельно с помощью headless-браузера и ротирующих резидентских прокси, но поддержание этого стека в рабочем состоянии составляет большую часть работы. Crawling API объединяет оба компонента в один вызов: передайте ему URL с JavaScript-токеном, он рендерит страницу и возвращает готовый HTML для Gemini.
Держите границу чёткой в голове. Crawlbase загружает и рендерит страницу в чистый HTML или markdown. Gemini извлекает структурированные поля из этого контента. Gemini никогда не обращается к сети в этой архитектуре, а Crawlbase никогда не пытается понять данные. Смешение этих обязанностей, наиболее распространённая причина нестабильности таких конвейеров.
Что вы создадите
Небольшой запускаемый скрипт на Python, который принимает URL продукта, загружает отрендеренную страницу через Crawling API в виде чистого markdown, отправляет этот markdown в Gemini с промптом для извлечения и записывает структурированный результат в JSON-файл. Мы будем использовать публичную тестовую страницу, чтобы вы могли запустить каждый фрагмент как есть, прежде чем нацеливать его на реальную цель.
Настройка окружения
Вам нужен Python 3.8 или новее. Проверьте версию, создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, затем установите библиотеки.
python --version python -m venv gemini_env source gemini_env/bin/activate pip install google-generativeai crawlbase python-dotenv
В Windows активируйте окружение командой gemini_env\Scripts\activate вместо строки с source. Три зависимости выполняют основную работу: crawlbase является официальным клиентом для Crawling API, google-generativeai является клиентом Google для Gemini, а python-dotenv загружает ваши ключи из локального файла, чтобы они никогда не оказались жёстко прописаны в скрипте.
Вам нужны два учётных данных. Получите API-ключ Gemini в Google AI Studio и JS-токен Crawlbase в панели управления Crawlbase после регистрации. Сохраните оба в файле .env в папке проекта.
GEMINI_API_KEY=your_gemini_key_here CRAWLBASE_JS_TOKEN=your_crawlbase_js_token_here
Crawlbase предлагает два типа токенов. Обычный токен получает статичный HTML; JavaScript (JS) токен сначала рендерит страницу в реальном браузере. Большинство страниц, заслуживающих скрапинга, загружают контент на стороне клиента, поэтому JS-токен является безопасным вариантом по умолчанию. Использование обычного токена на клиентски-рендеримой странице вернёт ту же пустую оболочку, что и обычный запрос, а Gemini не сможет извлечь данные, которых там нет.
Шаг 1: Загрузка отрендеренной страницы через Crawling API
Crawling API может вернуть страницу, уже преобразованную в markdown, что идеально для отправки в LLM. Markdown отфильтровывает навигацию, скрипты и стилистический шум, оставляя читаемый контент. Это сокращает количество токенов, отправляемых в Gemini, что делает вызов дешевле, а извлечение точнее. Передайте параметр format: 'markdown', и API вернёт чистый текст вместо сырого HTML.
import os from dotenv import load_dotenv from crawlbase import CrawlingAPI load_dotenv() api = CrawlingAPI({"token": os.environ["CRAWLBASE_JS_TOKEN"]}) url = "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html" def fetch_markdown(target_url): options = {"format": "markdown", "ajax_wait": "true", "page_wait": 3000} response = api.get(target_url, options) return response["body"].decode("utf-8") page_markdown = fetch_markdown(url) print(page_markdown[:500])
Оба параметра ожидания важны для клиентски-рендеримых целей. ajax_wait указывает API дождаться завершения загрузки асинхронного контента, а page_wait задерживает выполнение на фиксированное количество миллисекунд после загрузки, чтобы поздно рендеримые элементы появились до захвата страницы. Трёх секунд достаточно для начала; увеличьте значение, если контент возвращается неполным. Для статической страницы, такой как тестовая книга выше, можно даже использовать обычный токен, но сохранение JS-токена и этих параметров означает, что тот же код работает при переключении на более сложный, клиентски-рендеримый сайт.
Gemini читает страницы, но не загружает их. Crawling API закрывает этот пробел в одном вызове: передайте JS-токен, он рендерит страницу в реальном браузере, ротирует резидентские IP на стороне сервера и возвращает чистый HTML или markdown, готовый для LLM, избавляя вас от необходимости управлять headless-флотом и пулом прокси самостоятельно. Начните с публичной страницы на бесплатном уровне.
Шаг 2: Отправка контента в Gemini и запрос JSON
Теперь самое интересное. Имея чистый markdown, опишите нужные поля в промпте и позвольте Gemini выполнить извлечение. Ключевой приём для надёжного конвейера, принудительный вывод JSON. Клиент Gemini поддерживает MIME-тип ответа, поэтому установите его в application/json, и модель вернёт разбираемый JSON вместо прозы с обёрткой из code-fence. Эта единственная настройка устраняет большую часть нестабильности, на которую жалуются при извлечении с помощью LLM.
import google.generativeai as genai genai.configure(api_key=os.environ["GEMINI_API_KEY"]) model = genai.GenerativeModel("gemini-2.0-flash") def extract_fields(content): prompt = f"""You are a data extraction tool. From the page content below, extract the book title, price, availability, and star rating. Return only JSON with keys: title, price, availability, rating. CONTENT: {content} """ response = model.generate_content( prompt, generation_config={"response_mime_type": "application/json"}, ) return response.text raw_json = extract_fields(page_markdown) print(raw_json)
Несколько вещей делают этот промпт работающим. Он задаёт роль («инструмент извлечения данных»), чтобы Gemini был лаконичным, называет точные ключи, которые вам нужны, чтобы схема была стабильной между прогонами, и передаёт markdown, а не сырой HTML, чтобы модель тратила своё внимание на контент, а не на шаблонный код. Если вам нужна более богатая схема, перечислите больше ключей и опишите неоднозначные; модель обрабатывает вложенные объекты и массивы без лишних усилий.
Шаг 3: Парсинг и сохранение структурированного результата
Поскольку вы запросили JSON MIME-тип, текст ответа уже является валидным JSON. Разберите его в словарь Python и запишите на диск. Оберните парсинг в try/except, чтобы редкий некорректный ответ логировал сырой текст вместо аварийного завершения прогона.
import json def save_json(raw, path="book_data.json"): try: data = json.loads(raw) except json.JSONDecodeError: print("Gemini did not return valid JSON:") print(raw) return with open(path, "w") as f: json.dump(data, f, indent=2) print(f"Saved {path}") save_json(raw_json)
Полный скрипт
Вот всё объединённое в один запускаемый файл. Заполните оба учётных данных в .env, измените URL и скорректируйте ключи промпта под извлекаемую цель.
import os import json from dotenv import load_dotenv from crawlbase import CrawlingAPI import google.generativeai as genai load_dotenv() api = CrawlingAPI({"token": os.environ["CRAWLBASE_JS_TOKEN"]}) genai.configure(api_key=os.environ["GEMINI_API_KEY"]) model = genai.GenerativeModel("gemini-2.0-flash") url = "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html" def fetch_markdown(target_url): options = {"format": "markdown", "ajax_wait": "true", "page_wait": 3000} response = api.get(target_url, options) return response["body"].decode("utf-8") def extract_fields(content): prompt = f"""You are a data extraction tool. From the page content below, extract the book title, price, availability, and star rating. Return only JSON with keys: title, price, availability, rating. CONTENT: {content} """ response = model.generate_content( prompt, generation_config={"response_mime_type": "application/json"}, ) return response.text def main(): markdown = fetch_markdown(url) raw = extract_fields(markdown) try: data = json.loads(raw) except json.JSONDecodeError: print("Gemini did not return valid JSON:", raw) return with open("book_data.json", "w") as f: json.dump(data, f, indent=2) print(json.dumps(data, indent=2)) if __name__ == "__main__": main()
Как выглядит результат
Запустите командой python scraper.py и получите чистые структурированные данные, записанные в book_data.json и выведенные в консоль.
{ "title": "A Light in the Attic", "price": "£51.77", "availability": "In stock (22 available)", "rating": "Three" }
Обратите внимание на то, что вы не писали: ни CSS-селекторов, ни XPath, ни логики парсинга отдельных полей. Вы описали поля, и модель их нашла. Нацельте тот же скрипт на другой URL книги или страницу товара на другом сайте, и он адаптируется без изменений кода, что и является реальным преимуществом подхода извлечения данных с помощью AI перед ручной настройкой селекторов.
Масштабирование на множество страниц
Одна страница, это демонстрация; реальная задача выполняется по списку URL. Структура остаётся той же: обходите URL, загружайте каждый через Crawling API, извлекайте с помощью Gemini и собирайте строки. Две вещи стоит иметь в виду при масштабировании. Gemini выставляет счёт за токены, поэтому отправка markdown вместо полного HTML снижает стоимость каждого вызова, а Crawling API имеет собственную пропускную способность, поэтому вам не нужно управлять прокси или экземплярами браузера самостоятельно.
urls = [ "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html", "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html", ] results = [] for u in urls: markdown = fetch_markdown(u) raw = extract_fields(markdown) try: results.append(json.loads(raw)) except json.JSONDecodeError: print(f"Skipped {u}: invalid JSON") with open("books.json", "w") as f: json.dump(results, f, indent=2)
Если вы обнаруживаете, что снова и снова извлекаете данные с одного хорошо известного сайта (Amazon, крупный ритейлер, доска объявлений о работе), стоит сравнить этот подход со Crawling API, который возвращает предварительно разобранный JSON для поддерживаемых сайтов без LLM в конвейере. Для необычных или разовых макетов, для которых парсер не существует, подход с Gemini, описанный в этом руководстве, является гибким запасным вариантом. Подробнее о том, почему markdown является правильным форматом входных данных для LLM, см. в markdown, готовый для LLM, в веб-скрапинге.
Ограничения, которые стоит знать перед запуском в промышленную среду
Конвейер Gemini и Crawlbase является гибким, но не универсальным инструментом. Имейте в виду следующее.
Стоимость токенов накапливается. Gemini выставляет счёт за отправленные и полученные токены. Отправка полного HTML вместо markdown может многократно увеличить счёт без какой-либо пользы, поэтому всегда сокращайте входные данные. Для очень больших страниц извлекайте только релевантный раздел перед вызовом LLM.
Это медленнее, чем парсинг по правилам. Вызов LLM занимает больше времени, чем проход Cheerio или BeautifulSoup по селектору. Для высокочастотных задач с низкой задержкой, таких как мониторинг цен посекундно, выделенный парсер выигрывает. Подход с LLM проявляет свои преимущества, когда макеты варьируются или часто меняются.
Модели могут ошибаться. На плотных или повторяющихся страницах модель иногда может неправильно пометить или пропустить поле. Принудительный вывод JSON и указание точных ключей значительно снижают это, но для всего критически важного проверяйте разобранный словарь по ожидаемой схеме, прежде чем ему доверять.
Для поддержания работоспособности при больших объёмах Crawling API управляет ротацией IP и рендерингом за вас. Если вы предпочитаете маршрутизировать собственный трафик через ротирующий пул, Smart AI Proxy (также называемый AI Proxy) даёт ту же ротацию резидентских IP в виде подключаемой конечной точки прокси. В любом случае общая стратегия изложена в руководстве по скрапингу сайтов без блокировок.
Ключевые выводы
- Разделите задачи. Crawlbase загружает и рендерит страницу; Gemini извлекает поля. Ни один инструмент не делает работу другого, и именно это разделение делает конвейер надёжным.
-
Используйте JS-токен и формат markdown. JS-токен рендерит клиентски-рендеримые страницы;
format: 'markdown'возвращает чистый, малотокенный контент, идеальный для LLM. -
Принудительно выводите JSON. Установите
response_mime_typeGemini вapplication/jsonи называйте точные ключи, чтобы результат был разбираемым при каждом прогоне. - Селекторы не нужны. Вы описываете поля на обычном языке, поэтому тот же скрипт адаптируется к разным макетам без переписывания кода извлечения.
- Знайте компромиссы. Извлечение с помощью LLM гибко, но медленнее и оплачивается за токены, поэтому сокращайте входные данные, проверяйте вывод и используйте выделенный парсер, когда важна скорость.
Часто задаваемые вопросы
Может ли Gemini самостоятельно выполнять веб-скрапинг?
Не в части загрузки. Gemini читает и структурирует контент, который вы ему передаёте, но у неё нет HTTP-клиента, браузера или пула прокси, поэтому она не может открыть URL или обойти антибот-защиту. Вы объединяете её со слоем загрузки, таким как Crawling API, который рендерит страницу и возвращает чистый HTML или markdown; Gemini затем извлекает структурированные поля из этого контента.
Зачем конвертировать страницу в markdown перед отправкой в Gemini?
Markdown отфильтровывает навигацию, скрипты и стилистический шум, оставляя читаемый контент. Это снижает количество токенов, отправляемых в Gemini, что снижает стоимость и повышает точность, поскольку модель тратит внимание на реальный контент, а не на шаблонный код. Crawling API может возвращать markdown напрямую с параметром format: 'markdown', поэтому отдельный шаг конвертации не нужен.
Нужен ли обычный токен или JS-токен от Crawlbase?
Используйте JS-токен для любой страницы, рендерящей контент на стороне клиента, что характерно для большинства современных сайтов. Обычный токен получает статичный HTML, поэтому на клиентски-рендеримой странице он возвращает пустую оболочку и Gemini нечего извлекать. JS-токен рендерит страницу в реальном браузере, поэтому контент присутствует, когда достигает модели.
Как заставить Gemini стабильно возвращать JSON, а не прозу?
Установите response_mime_type в конфигурации генерации в application/json и назовите точные ключи, которые хотите получить, в промпте. Такое сочетание заставляет Gemini возвращать разбираемый JSON без обёрток code-fence или комментариев. Всё равно оборачивайте вызов json.loads в try/except, чтобы редкий некорректный ответ логировал сырой текст вместо аварийного завершения прогона.
Подход с Gemini лучше Scraper API для всего?
Нет, они служат разным целям. Для хорошо известных сайтов с существующими парсерами Scraper API возвращает предварительно разобранный JSON быстрее и без стоимости токенов LLM. Конвейер с Gemini является гибким запасным вариантом для необычных, разовых или часто меняющихся макетов, для которых выделенный парсер не существует и вы предпочитаете описывать поля, а не поддерживать селекторы.
Заблокируют ли меня?
Crawling API рендерит страницы за ротирующими резидентскими IP на стороне сервера, что обрабатывает большинство блокировок за вас. Если вы создаёте собственный стек загрузки, именно в ротацию стоит инвестировать, и вы можете использовать Smart AI Proxy в качестве подключаемой ротирующей конечной точки. Задавайте темп запросов, варьируйте цели и следите за кодами статусов, чтобы снизить активность, когда сайт начинает проверять трафик.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
