Парсинг с помощью LLM: зачем, как и сколько стоит?
Во всю идет 2025 год, и нейросети перестают быть чем-то фантастическим. Они уже повсюду в нашей жизни: от умных колонок в квартирах до сложнейших систем, управляющих логистикой и финансами. Вместе с ними стремительно меняется подход к работе с данными. В этой статье мы поговорим о том, как современные LLM помогают автоматизировать сбор данных с веб-сайтов и сводят к минимуму рутинную настройку и «подкручивание» парсеров.

Что еще вы найдете в этой статье?
Разберемся, как большие языковые модели упрощают процесс парсинга и в каких случаях они особенно эффективны.
Обсудим финансовую сторону вопроса и дадим ориентиры по бюджету, чтобы вы смогли понять, подходит ли этот путь именно вам.
Обсудим, как и для чего еще можно применять эти подходы на практике.
Для кого эта статья?
Для разработчиков и дата-аналитиков, которые хотят расширить свой стек инструментов по сбору данных и повысить скорость разработки парсеров.
Для руководителей проектов и бизнесменов, которые хотят оптимизировать затраты на сбор данных и повысить эффективность.
Для тех, кто следит за трендами в мире LLM и машинного обучения и хочет увидеть, как эти технологии работают на реальных примерах.
В качестве примеров кода я буду использовать Python. Полный код представленных примеров можно скачать с Github.
Как сейчас мы парсим данные с веб-сайтов
Классический способ собрать информацию с сайта — написать набор скриптов, которые обработают HTML и вытянут нужные фрагменты: текст, ссылки, цены, характеристики, телефоны, почты и т. д. Для этого есть популярные библиотеки вроде requests на python. А для асинхронной работы httpx, aiohttp. Для разбора HTML старый добрый Beutifulsoup. Ну и конечно фреймворки, типа Scrapy. Если сайт рендерит содержимое на стороне клиента с помощью JavaScript, в ход идут Selenium, Playwright или Puppeteer — инструменты, которые позволяют управлять браузером и парсить уже прорендеренную страницу.
Главная идея всех этих подходов — это в явном виде прописать, какие элементы HTML страницы нужно вытащить. Например, чтобы в найти div с классом .product-info или спарсить теги , в которых хранится цена. На помощь приходят XPath и CSS-селекторы, а иногда — регулярные выражения. Например, чтобы в Scrapy спарсить информацию о продукте с помощью CSS или XPath, нужно написать примерно такую конструкцию:
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example_spider"
start_url = ["https://example.com/"]
def parse(self, response):
# Извлекаем текст информации о продукте с помощью CSS
product_info = reponse.css("div.product-info::text").get()
# Извлекаем цену, предположим, она находится в
product_price = response.css("span.price::text").get()
yield {
"product_info": product_info,
"product_price": product_price
}
Тоже самое при помощи XPath:
...
# Извлекаем текст информации о продукте при помощи XPath
product_info = response.xpath("//div[@class='product-info']/text()").get()
# Извлекаем цену с XPath
product_price = response.xpath("//span[@class='price']/text()").get()
...
Такой подход отлично работает, но требует постоянной поддержки. Стоит владельцам сайта немного изменить верстку, добавить новые классы или изменить структуру — парсер ломается или собирает некорректные данные.
А что если нужно парсить не один и тот же сайт? Что если нужно собирать данные одновременно с десятков или даже сотен ресурсов? Тут сложности умножаются: набор селекторов, регулярных выражений и дополнительных «костылей» растет в геометрической прогрессии.
Нет ли способа сделать весь этот процесс гибче? Чтобы меняющаяся структура сайтов не ломала скрипты. А обновления верстки отлавливались автоматически. Именно вот здесь, на этих вопросах, все заметнее становятся решения на базе нейросетей.
Делаем запросы к LLM по API
Когда речь заходит о «парсинге с помощью нейросетей», можно представить себе громоздкую историю с обучением моделей, сбором датасетов и сложной инфраструктурой. На деле же ситуация упростилась благодаря готовым моделям, типа GPT. Не нужно «учить» нейронную сеть с нуля — достаточно воспользоваться публичным API, указывая, какой именно результат вы хотите получить. Перейдем к примерам.
Давайте для начала напишем простой запрос к веб-сайту, чтобы получить его структуру HTML. Я буду использовать requests, предварительно установив его.
import requests
def scrape_html(url: str) -> str:
response = requests.get(url)
return response.text
Здесь все довольно просто: написали функцию, которая на вход принимает URL документа, делает к нему HTTP-запрос и возвращает HTML целиком. Получили весь HTML-код документа. Теперь нужно передать его модели GPT для обработки.
Я возьму для примера сайт, который специально был создан для обучения парсингу для тех, кто только начинает свой путь, а также, для отладки парсеров более опытных разработчиков. Возможно вы видели и знаете этот сайт: http://books.toscrape.com/.

На первой странице представлен список книг с названием, ценой, наличием рейтингом и другими параметрами. Для простоты эксперимента я выберу 3 параметра для парсинга: название книги, цена и рейтинг. В качестве модели будет работать GPT-4o.
Итак, пишем обращение к модели по API:
from openai import OpenAI
# здесь должен быть ваш ключ API
OPENAI_API_KEY = "openai_api_key"
# создание объекта OpenAI
client = OpenAI(api_key=OPENAI_API_KEY)
def extract_info(content: str):
# прописываем системный промпт
system_message = {
"role": "system",
"content": "Получи цену и рейтинг на все книги со страницы строго в json формате: {book: str, price: float, rating: int}."
}
messages = [system_message]
# добавляем в промпт HTML-код документа
messages.append({"role": "user", "content": content})
# делаем запрос к API
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
# формат ответа json
response_format={"type": "json_object"}
)
# возвращаем ответ
return response.choices[0].message.content
Пояснения к коду выше
Для начала, нужно установить библиотеку openai:
pip install openai
Далее импортируем оттуда класс OpenAI. Создаем объект этого класса. Здесь понадобится ключ API. Как его получить, подробно написано в этом руководстве: https://vc.ru/ai/1654874-openai-api-kak-ispolzovat-na-praktike-v-seo.
Затем, пишем системный промпт, в котором указываем, какие параметры нужно спарсить со страницы и строго определяем, в каком формате эти данные нужно получить на выходе. Я указываю следующее:
Получи цену и рейтинг на все книги со страницы строго в json формате: {book: str, price: float, rating: int}.
Значение типизации данных и формата ответа
Обратите внимание, что я строго прописал типы выходных данных для каждого параметра: Название книги: строка, цена: число с точкой, рейтинг: целое число. Указывая типы данных в системном промпте (book: str, price: float, rating: int), мы создаем четкую схему, которую модель должна соблюдать. Это решает две важные задачи:
Устраняет двусмысленность интерпретации. Когда цена, например, может вернуться как строка »£51.77».
Работает в связке с response_format={«type»: «json_object»}. response_format — это встроенный атрибут в API OpenAI. Он позволяет получать структурированный JSON, который в дальнейшем можно использовать. А также, такой формат снижает вероятность ошибок и лишних данных, когда модель начинает пояснять свой ответ.
После формирования системного промпта, мы передаем HTML-содержимое страницы в качестве пользовательского сообщения в messages и делаем запрос к API.
Расчет стоимости парсинга с OpenAI API
Перед тем, как получить ответ, давайте напишем функцию, которая будет подсчитывать стоимость нашего парсинга в режиме реального времени. Это критически важно, ведь нам нужно понимать экономическую эффективность применения LLM в сравнении с традиционными парсерами. При масштабировании решения на десятки и сотни страниц, даже небольшая стоимость запроса может вылиться в существенную сумму.
Для точного подсчета токенов используем библиотеку tiktoken, которая применяет тот же алгоритм токенизации, что и API OpenAI. Она позволяет подсчитать количество токенов на input и на output, чтобы в дальнейшем определить общую стоимость.
Простая функция, которая считает количество токенов, модель стандартно передаем gpt-4o.
def count_tokens(text, model="gpt-4o"):
# Подсчет количества токенов в тексте
encoding = tiktoken.encoding_for_model(model)
return len(encoding.encode(text))
И функция, которая вычисляет и возвращает стоимость для input, output и итоговую.
def calculate_cost(input_tokens, output_tokens, model="gpt-4o"):
# Расчет стоимости запроса на основе количества токенов
rates = {
"gpt-4o": {"input": 5, "output": 15},
"gpt-3.5-turbo": {"input": 0.5, "output": 1.5}
}
input_cost = input_tokens * rates[model]["input"] / 1_000_000
output_cost = output_tokens * rates[model]["output"] / 1_000_000
return {
"input_cost": input_cost,
"output_cost": output_cost,
"total_cost": input_cost + output_cost
}
В rates можно добавить в таком же формате любые модели, чтобы потом передать ее для подсчета стоимости в параметре model функции calculate_cost (). С подробным прайсом на модели OpenAI можно ознакомится на этой странице https://platform.openai.com/docs/pricing.
Запуск парсера и получение результатов
Осталось объединить все и запустить парсер:
URL = "http://books.toscrape.com/"
MODEL = "gpt-4o"
client = OpenAI(api_key=OPENAI_API_KEY)
html_content = scrape_html(URL)
input_tokens = count_tokens(html_content, MODEL)
# Извлечение информации
result = extract_info(html_content, client, MODEL)
# Подсчет выходных токенов
output_tokens = count_tokens(result, MODEL)
# Расчет стоимости
cost = calculate_cost(total_input_tokens, output_tokens, MODEL)
# Отчет о стоимости
print("\n--- ОТЧЕТ О СТОИМОСТИ ПАРСИНГА ---")
print(f"Модель: {MODEL}")
print(f"Входные токены: {input_tokens:,} (${cost['input_cost']:.4f})")
print(f"Выходные токены: {output_tokens:,} (${cost['output_cost']:.4f})")
print(f"ИТОГО: ${cost['total_cost']:.4f}")
# Парсим JSON-ответ
parsed_data = json.loads(result)
# Вывод результатов
print("\n--- РЕЗУЛЬТАТЫ ПАРСИНГА ---")
print(f"Всего книг извлечено: {len(parsed_data['books'])}")
print("\nПример данных (первые 3 книги):")
for i, book in enumerate(parsed_data['books'][:3]):
print(f"{i+1}. {book['book']} - £{book['price']} - {book['rating']} звезд")
# Сохранение результатов в файл
with open("parsed_books.json", "w", encoding="utf-8") as f:
json.dump(parsed_data, f, ensure_ascii=False, indent=2)
print(f"\nРезультаты сохранены в файл parsed_books.json")
И наконец, давайте посмотрим результаты, которые получились с первого запуска:

Сначала, обратите внимание на результаты парсинга. У меня получился структурированный JSON, который сохранился в файл. Это валидный JSON без единой ошибки.

Все типы данных соответствуют тому, что мы хотели. Названия книг, цены, рейтинг — все ОК. Больше всего мне было интересно, как модель справится с парсингом рейтинга книги. Ведь на странице рейтинг книги выводится с помощью CSS соответствующего класса.

Например, если рейтинг книги — 3 звезды, то назначается класс Three, в котором настроено отображение 3 звезд, вот так:

Модель на отлично справилась с этой задачей. Она по названию класса перевела все рейтинги в целые числа. В обычном парсере, чтобы решить подобную задачу, нужно писать, как минимум, отдельный обработчик с несколькими if-else. Здесь же мы просто написали строчку: rating: int и на этом все. Это похоже на волшебство! Я постоянно использую нейросети и все равно удивляюсь и радуюсь в такие моменты :).
Стоимость парсинга с применением OpenAI API
Почти 10 тыс. токенов пришло на вход модели, что и составило наибольшую стоимость. Всего для парсинга 1 страницы из 20 книг потратили $0.0602. Если бы нам захотелось спарсить все 50 страниц со списками книг, то в общем мы бы потратили чуть больше $3.
Много это или мало? Ответ зависит от контекста. Так что здесь я предлагаю вам самим поразмышлять и, возможно, написать в комментариях ваши мысли.
Reader от Jina.ai
А теперь мы рассмотрим решение, которое сможет сократить количество входящих токенов, а следовательно, и общую стоимость парсинга. Это продукт jina.ai — Reader. Этот инструмент преобразует HTML в формат, удобный для ввода LLM — формат Markdown. Когда мы передаем полный необработанный HTML, в структуре присутствует большое количество посторонних элементов (разметка, скрипты). Для модели все это не представляет ценности, но влияет на стоимость запроса. Reader очищает страницу от ненужных элементов, предоставляя модели только полезную информацию в удобном для нее формате Markdown.
Все что нужно, это добавить вначале запрашиваемого URL: https://r.jina.ai/ Попробуйте сами проделать это в вашем браузере. Ответ должен получится примерно такой:

Давайте попробуем добавить это в код.
html_content = scrape_html("https://r.jina.ai/" + URL)
И посмотрим, что получится.

Количество входящих токенов сократилось в 3 раза: с 10 тыс. до 2.8 тыс.! Очень даже неплохой результат. Итоговая стоимость уменьшилась в 2 раза. Несмотря на то, что в структуре страницы, которую отдает https://r.jina.ai/books.toscrape.com я не нашел рейтинга книг, он все таки сохранился в json файл. Я не знаю как это сработало, но это просто факт :) Скорее всего, данные по рейтингам модель просто придумала и они окажутся неточными, поэтому перед парсингом с reader от jina.ai нужно смотреть, есть ли вероятность того, что данные просто не исчезнут после очистки.
Использование нейросетей для классификации и «умного» извлечения данных
Помимо прямого извлечения конкретных полей (цены, названия, характеристик), нейросети можно применять для более продвинутых задач, например, для классификации и категоризации контента. Допустим, у вас есть список из сотен сайтов, и вам нужно понять, о чем тот или иной ресурс: что это за тематика, присутствует ли там конкретный тип товаров или услуг, есть ли определенные триггерные слова (например, «купить», «доставка», «подписка»).
Вместо того чтобы скачивать весь контент и парсить его вручную, можно отдать LLM лишь часть информации, нужную для принятия решения. К примеру, для определения тематики или типа сайта можно ограничиться только информацией из семантических тегов: