Price Monitor: LLM-экстракция цен дилеров
Ежемесячный контроль MAP по всему рынку дилеров Samsung Medison в РФ. Трёхуровневый pipeline (JSON-LD → LLM → эвристика) на Claude Haiku 4.5 и SerpAPI.
Коротко
- Задача — контроль Minimum Advertised Price (MAP) по 6 моделям УЗ-сканеров Samsung на всём рынке дилеров РФ. Раньше — ручной обход сайтов раз в месяц.
- Подход — 3-уровневый pipeline экстракции цены: JSON-LD schema.org → контекстная LLM-экстракция на Claude Haiku → regex-эвристика как fallback.
- Объём — 6 моделей × 6 query-шаблонов × 2 поисковика × 5 страниц выдачи = ~1 000 уникальных URL за прогон. 30–45 минут до Excel-отчёта.
- Экономика — ~$5 за полный прогон. SerpAPI ≈ $3–4, LLM ≈ $2–4. 2–3 прогона в месяц укладываются в квоту 1 000 SerpAPI-запросов.
Цифры, которые можно сверить
- Моделей сканеров под контролем
- 6
- URL за один прогон
- ~1 000
- Время прогона
- 30–45 мин
- Стоимость одного прогона
- ~$5
- SerpAPI-вызовов за прогон
- 360
- Уровней в pipeline экстракции
- 3
Зачем это бизнесу
У дистрибьютора есть утверждённая ценовая политика: дилер не может рекламировать скидку больше 45% от прайса. Без контроля эта политика быстро размывается — один дилер демпингует, остальные подстраиваются, маржа уходит, головной офис в Корее задаёт вопросы.
Контролировать вручную не получится. Только на 6 активных моделях — сотни дилерских сайтов, у каждого свой шаблон карточки товара, у каждого свой язык. И цены меняются между прогонами.
Нам нужно было собрать систему, которая раз в месяц делает то же самое, что ответственный сотрудник, — только быстрее, точнее и с воспроизводимым результатом.
Это одна из тех систем, про которые не надо громко говорить. Она просто работает каждый месяц и экономит дистрибьютору часы ручной работы и десятки процентов маржи.
Как это работает — за один прогон
- Поиск. Для каждой из 6 моделей (V6, V7, V8, W9, W10, Z20) — 6 поисковых запросов × 2 движка (Google и Yandex, включая Yandex Market) × 5 страниц выдачи. Итого 60 вызовов SerpAPI на модель, 360 на прогон.
- Пре-фильтры. Выбрасываем заведомо «шумные» страницы: прайс-листы, каталоги, страницы «б/у / демо / восстановленный», мультибрендовые витрины, страницы без упоминания целевой модели.
- Экстракция цены по 3-уровневой схеме. Первый уровень, который вернул валидную цену, — выигрывает.
- Сравнение с прайсом. Берём курс EUR/RUB с CBR РФ, прибавляем 2% надбавки, считаем допустимый минимум:
list_price × (1 − 0.45). Если цена ниже — ALARM. Если выше прайса × 1.3 — возможно, собрано с датчиками в комплекте (аномалия). - Отчёт. Excel с тремя листами: «Нарушители», «Все результаты», «Сводка». В «Все результаты» цветовая разметка: зелёное — норма, красное — нарушение, оранжевое — аномалия, серое — цены нет.
3-уровневый pipeline экстракции
Это сердце системы. Почему именно три уровня — каждый закрывает свои случаи.
Уровень A — JSON-LD schema.org (бесплатно)
Читаем <script type="application/ld+json"> на странице. Ищем Product / Offer с price и priceCurrency. Если магазин корректно размечен — это авторитетный источник, цена попадает в отчёт без привлечения LLM. Покрывает 30–50% e-commerce-сайтов.
SEO-ghost guard. Отдельный защитный слой: принимаем JSON-LD-цену только если то же число встречается в видимом тексте страницы. Многие дилеры зашивают в микроразметку «SEO-цену» для ранжирования в Google, а на самой странице показывают «Запросить цену». Без проверки такие страницы давали бы ложные ALARM.
Уровень B — LLM-экстракция (Claude Haiku 4.5 через OpenAI-совместимый proxy)
Если JSON-LD не дал результата — отправляем текст страницы, URL и курс EUR/RUB в модель со строгим системным промптом. Модель возвращает {"price": int|null, "reason": "..."}.
Что умеет промпт:
- Отличать цену целевой модели от цен других Samsung-моделей в блоках «Похожие товары».
- Отбрасывать цены конкурирующих брендов (Mindray, GE, Philips, Esaote и десятки других) — у них общие страницы сравнения встречаются регулярно.
- Игнорировать цены датчиков, принтеров, расходников.
- Не путать лизинговые платежи («первый взнос», «в месяц») с ценой аппарата.
- Выбрасывать б/у и демо-оборудование.
- Корректно конвертировать EUR → RUB по переданному курсу.
- Возвращать
null, если на странице «цена по запросу» или нет числа для целевой модели.
Ключевое архитектурное решение: если LLM сказал null, мы не проваливаемся в regex-fallback. Доверяем модели. Иначе эвристика уверенно подтягивает первую попавшуюся сумму из подвала с «запчасти от 15 000 ₽».
Уровень C — regex + DOM-эвристика (fallback)
Работает, когда LLM-этап выключен или ключ LLM не задан. Собственный парсер цен с набором правил: \b перед числом, чтобы iGo2 290 000 руб не читалось как 2 290 000 руб; разделители текстовых нод через separator=" ", чтобы Запросить КП и 4 773 627 ₽ не склеились в одну «4-миллионную» строку; фильтр по диапазону 500 тыс — 50 млн ₽.
Почему это вообще нетривиально
Если кажется, что «просто обход сайтов и regex», — нет. Вот несколько «маленьких» кейсов, которые съедают недели без LLM-этапа:
- Похожие товары. На странице V7 карусель «Похожие» показывает V8 с ценой — нативный регекс не различает, о какой модели идёт речь.
- Мультибрендовые витрины. На одной странице Samsung + Mindray + GE Logiq — без контекстного понимания моделями в отчёте всё смешается.
- SEO-ghost. Микроразметка говорит «2 500 000», а на странице «Цена по запросу» — сайт получает преимущество в Google, а мы ловим ложный ALARM.
- Лизинг. «Первый взнос 290 000 ₽» выдаётся за цену аппарата.
- Б/у на той же странице. Сайт продаёт и новый, и б/у V6 в одной карточке — без проверки соседнего контекста выбирается первое число.
Для каждого из этих случаев в системе есть отдельное правило. Но чем больше таких «подкейсов» накапливается, тем хрупче становится чистый regex. Поэтому LLM-этап — не роскошь, а инструмент стабильности.
Экономика и масштаб
- Полный прогон по 6 моделям — 360 SerpAPI-запросов, ~1 000 уникальных URL для скрапинга и анализа.
- Время — 30–45 минут от запуска до готового Excel.
- Стоимость — около $5 за прогон: $3–4 на SerpAPI, $2–4 на LLM. Месячная квота SerpAPI 1 000 = 2–3 полных прогона.
- Защита от дорогих повторов —
rescrape_from_report.py: если нужно пересчитать только URL из предыдущего отчёта (например, после доработки правил), SerpAPI не дёргается вовсе.
Что делает система, кроме самой экстракции
- Автоматически берёт курс EUR/RUB с CBR РФ и добавляет 2% надбавки к списочной цене.
- Дедупликация: одна цена на дилера и модель (ключ
domain|model). - Excel-отчёт с цветовой разметкой, отдельным листом нарушителей, листом всех результатов и сводкой по курсам и референсным прайсам.
- PDF-спецификация по моделям для использования в согласованиях внутри компании.
Что здесь показательно как инженерный кейс
- LLM не вместо правил, а как инструмент в правильном месте pipeline. Сначала — дешёвый и быстрый JSON-LD, потом дорогая модель, потом regex как последний рубеж.
- Доверие к модели важнее формальной полноты. Если модель сказала «не знаю» — значит, не знаем и мы. Попытка «докрутить регексом» ломает точность.
- Защиты от ложных срабатываний — отдельный пласт работы. SEO-ghost, мультибрендовые страницы, лизинг, б/у — каждый случай реальный и приходит с продакшна.
- Экономика под квоту. Система не пытается «обойти интернет», она точно укладывается в месячную квоту SerpAPI и в разумный LLM-бюджет.
Что из этого кейса можно забрать себе
- MAP-контроль, парсинг цен конкурентов, мониторинг дилеров — задача, которая почти в любой отраслевой B2B-компании есть, но почти нигде не решена системно.
- Контекстная LLM-экстракция — хороший инструмент в любых случаях, где «данные есть, но в разметке их нет»: отзывы, описания товаров, характеристики, прайс-листы в PDF.
- Формат Excel с цветовой разметкой — такие отчёты команда коммерции и бухгалтерия читают быстрее, чем любой дашборд.
Если у вас есть задача мониторинга цен, парсинга распределённых источников или извлечения структурированных данных из «грязного» текста — напишите мне в Telegram. Обсудим, укладывается ли ваша задача в похожую архитектуру.