Сижу в понедельник утром — открываю дашборд и вижу: конкурент за ночь опустил цену на 23%. Моя — осталась. Продажи просели. И вот вопрос — почему я узнаю об этом через дашборд, а не раньше?
Когда я первый раз задумался про мониторинг цен конкурентов, пошёл по стандартному пути: нагуглил готовые сервисы, посмотрел цены. Ценообразование у большинства — по URL или по SKU, плюс подписка за каждого конкурента. Мне нужно было мониторить 12 магазинов, и выходило $400–800 в месяц. Окей, думаю — а что если собрать своего агента? За один уикенд?
Так родился проект, который сейчас работает на VPS за $6 в месяц. Не потому что я гений — а потому что задача проще, чем кажется.
Что делает такой агент — если отбросить маркетинг
По сути это пайплайн из трёх этапов: забираем HTML страниц конкурентов, парсим нужное значение из DOM, а дальше сравниваем, решаем, уведомляем.
На бумаге всё элементарно. На практике на каждом из этих этапов есть подвох.
Сбор данных: где всё ломается
Сначала я написал простой скрипт на requests и BeautifulSoup. Красиво, быстро, работает. Ровно до того момента, пока страницы конкурентов не начали возвращать капчу или редирект на мобильную версию. Один магазин вообще отдавал цену только авторизованным пользователям — первый запрос шёл на форму входа.
Решение: headless-браузер. Playwright или Puppeteer. Не потому что без него нельзя — а потому что экономишь два дня на отладку «почему цена не спарсилась». Playwright ещё умеет ждать появления элемента, что критично для SPA-сайтов, которые рендерят цены через JS уже после загрузки HTML.
Пример на Playwright:
from playwright.sync_api import sync_playwright
def get_price(url):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url, wait_until='networkidle')
# Ждём цену — до 10 секунд
price_elem = page.wait_for_selector('.price', timeout=10000)
price_text = price_elem.inner_text()
browser.close()
return extract_number(price_text)
Но и здесь есть грабли. Многие сайты определяют headless-браузеры по отпечатку и подсовывают заглушку. Поэтому в продакшене я добавил смену User-Agent и отключение webdriver-флага. Мелочь, а раз в неделю экономит нервы.
Парсинг цены: универсального селектора не существует
Это был самый утомительный этап. У каждого конкурента цена лежит в своём элементе: где-то data-price, где-то внутри SVG, где-то формируется JS-скриптом и подгружается отдельно. Сначала я написал 12 парсеров под каждую площадку. Это работало, но ломалось при каждом редизайне.
Сейчас у меня два слоя. Жёсткий селектор для стабильных магазинов — если магазин обновляет вёрстку раз в год, не вижу смысла городить огород. И LLM-помощник для страниц, где селектор не работает или страница непредсказуемо меняется: кидаю в GPT-4o текст страницы и прошу вытащить цену. Звучит костыльно, но экономит часы ручной работы. Стоимость — $0.001–0.003 на запрос. При моих 300 проверках в день это примерно $9 в месяц.
Анализ: что считать изменением
Тут начинается собственно интеллект. Мониторить цену мало — важно понимать паттерн. Цена может упасть на 5% перед распродажей, а может — перед снятием товара с производства. Это разные ситуации, требующие разной реакции.
Я завёл простую логику на порогах. Изменение меньше 2% — игнорировать, может быть погрешность округления. Между 2 и 10% — записать в лог и уведомить в Telegram. Больше 10% — срочное уведомление плюс запуск дополнительной проверки.
Но главное — я стал отслеживать тренд. Если цена конкурента падает третий раз за месяц, это сигнал. Для этого данные пишутся в SQLite (именно SQLite, потому что схема простая и мне не нужна БД на отдельном сервере), и раз в сутки скрипт строит простую скользящую среднюю по каждому SKU.
Уведомления: не спамь, но и не молчи
Почти сломал себе мозг на системе уведомлений. Сначала слал на почту — письма копятся, их никто не читает. Потом подключил Telegram-бота — и получил обратную связь: бот слишком болтливый.
Решение: тихий режим по умолчанию, громкий — только по порогу. Раз в день краткий дайджест. При изменении больше порога — сразу. Бот умеет отвечать на команды: «покажи топ падений за неделю», «покажи цену товара X у всех конкурентов».
Где я обжёгся
Четыре вещи, которые хотел бы знать заранее.
Rate limiting. Некоторые сайты банально банили IP после 10 запросов в минуту. Решение — random delay между запросами (2–8 секунд) и прокси на ротации, если мониторинг критичный.
Кэширование на стороне сайта. Пара магазинов отдавала закешированную цену для незалогиненных пользователей. Снижал частоту проверок для таких — раз в 6 часов вместо получаса.
Валюты и форматы. Цена «1 299 ₽», «1 299.-» и «1299 RUB» — три разных формата. Написал парсер, который нормализует всё к числу.
Технические работы у конкурента. Сайт лежит — скрипт получает ошибку — неправильно считает это падением цены. Добавил проверку HTTP-статуса: если код не 200, пропускать итерацию.
Из чего оно стоит сейчас
- VPS: $6/месяц (Hetzner, один vCPU, 2 GB RAM)
- Хранение: SQLite на диске, бэкап раз в сутки в S3-совместимое хранилище ($0.5/месяц)
- LLM: $8–12/месяц (GPT-4o-mini, хватает за глаза)
- Прокси: не использую, обошёлся random delay
Итого — $15–19 в месяц против $500+ за готовое решение. Задачу закрывает на 90%. Оставшиеся 10% — это edge cases, которые решаются по мере поступления.
Стоит ли оно того
Зависит от масштаба. Если у тебя 3 конкурента и 50 товаров — проще заплатить за сервис и не тратить выходные. Если 15 конкурентов, 500 SKU, и хочется видеть паттерны, а не просто цифры — собери своего агента. Это не ML-система из научной статьи, а прагматичный пайплайн на Python, который делает одну вещь хорошо.
Но вот что понял за месяцы работы: данные бесполезны без действий. Агент собирает — хорошо. Анализ находит — отлично. А дальше должен быть процесс: кто смотрит уведомления, кто принимает решение о ценовом ответе. Без этого мониторинг — это просто красивые графики, которые никто не открывает.
