Три часа ночи. Slack дёргается — бот прислал уведомление: «Конкурент X снизил цену на "Эту Штуку" с 2990 до 2490». Кто-то из команды сфотографировал, кинул в чат и написал «ну всё, приехали». А я сижу и понимаю, что полчаса назад мы уже могли бы среагировать — если бы не ждали, пока кто-то случайно заметит.
Раньше мониторинг цен у нас был устроен примитивно: раз в день человек открывал сайт конкурента, копировал цену, вставлял в таблицу. Работало? Работало. Но данные приходили с задержкой в сутки, человеческий фактор давал сбои, а когда конкурент устроил пятидневную акцию — мы узнали о ней на третий день, когда продажи уже просели.
Задачу я себе поставил простую: автоматизировать мониторинг так, чтобы данные по ценам конкурентов появлялись в реальном времени, а при значимых изменениях мне приходило уведомление. Плюс хотелось историю — чтобы потом можно было посмотреть динамику и понять, как конкурент играет с ценами перед праздниками.
Что взял за основу
Для агента я использовал связку из нескольких компонентов. Не буду утверждать, что это единственно правильный путь — просто расскажу, что получилось у меня.
Парсер страниц. Самая нудная часть. Конкуренты не дают API для доступа к ценам, поэтому пришлось разбираться с их HTML-структурой. Использовал Python + BeautifulSoup и Requests. Главная боль — конкуренты постоянно меняют вёрстку. Я потратил целый вечер на отладку одного парсера, потому что цену перенесли из одного DIV в другой, и XPath-сниппет перестал работать.
Проблему решил частично тем, что стал искать цену не по конкретному селектору, а по текстовому паттерну — «руб.», «₽», число рядом со словом «цена». Это оказалось надёжнее привязки к DOM-структуре.
LLM-обвязка. Сырые данные с парсера — это ещё не информация. Цена пришла, ок. А что с ней делать? Я написал промпт, который берёт текущую цену, сравнивает с последним известным значением и генерирует краткий вывод: «Конкурент X поднял цену на 12% — впервые за два месяца» или «Снижение на 500₽, совпадает с началом акции на главной странице». Без этой обвязки я бы получал поток цифр и тратил время на их интерпретацию.
Сначала я пытался обойтись без LLM — просто сравнивать числа. Но потом понял, что мне важно не только «цена изменилась», а «цена изменилась и вот что это значит». Промпт занял минут двадцать, результат — данные, которые действительно хочется читать.
База данных. Историю я решил хранить в SQLite. Просто, быстро, не требует настройки. Таблица простая: конкурент, товар, цена, дата, источник, примечание. Раз в неделю делаю бэкап — иначе терять данные как-то не хочется.
Планировщик. Скрипт запускается каждые 15 минут через cron. Не чаще — иначе можно получить бан от сервера конкурента. Агент перед каждым запросом проверяет, не делал ли он уже три запроса к этому домену за последний час. Если делал — пропускает цикл.
Уведомления. Отправляю в Telegram-бот. Выбрал Telegram, а не email, потому что бот присылает сообщение мгновенно, его удобно читать с телефона, и можно настроить фильтрацию — получать уведомления только если изменение больше 5% или касается определённых товаров.
Где я наступил на грабли
Первая версия упала через неделю. Проблема: конкурент заметил частые запросы с одного IP и на время заблокировал доступ. Агент начал писать в лог ошибки, а я узнал об этом только когда проверил статистику.
После этого добавил несколько защитных слоёв: ротация User-Agent, случайная задержка между запросами (от 3 до 8 секунд), и самое главное — проверка доступности сайта перед каждым циклом. Если конкурент начал отдавать капчу или 403 — скрипт об этом сообщает, а не тихо валится.
Вторая проблема: данные расходились с реальностью. Цена на сайте одна, а агент фиксировал другую. Оказалось, что конкурент подгружает актуальную цену через JavaScript, а парсер на Requests видел только начальную заглушку. Перешёл на Selenium — медленнее, но видит то же, что видит браузер. Это добавило оверхед, зато данные стали точными.
Третья проблема, и она дурацкая: я забыл про кэш на стороне конкурента. Иногда скрипт получал цену трёхчасовой давности. Решил принудительным обновлением через Ctrl+Shift+R в голове Selenium — добавил очистку кэша перед каждым запросом.
Что в итоге получилось
Агент работает уже четвёртый месяц. За это время:
Конкурент X снижал цену 11 раз — мы узнали о каждом снижении в течение 15 минут. Три раза мы успевали отреагировать до того, как это отражалось на наших продажах.
Выявили паттерн: конкурент всегда опускает цену за два дня до крупных маркетплейс-распродаж. Теперь мы заранее готовим предложение и не даём ему перехватить трафик.
Построили историю цен за квартал — она пригодилась для переговоров с поставщиками. «Вы видите, что рыночная цена упала на 18%? Почему ваша отпускная осталась той же?» — это работает.
Не всё гладко. Иногда Selenium ломается при обновлении Chrome — нужно пересобирать вебдрайвер. Раз конкурент полностью переделал сайт, и парсер не работал трое суток, пока я переписывал селекторы. Это боль, но это ожидаемо.
Коротко
Если хочешь сделать подобное — начни с простого. Возьми один товар, одного конкурента, напиши парсер, проверь, что он работает. Потом добавляй базу, уведомления, историю. Не пытайся сразу построить систему мониторинга всего рынка — утонешь в интеграциях.
Главное, что я понял: данные без действия — это просто шум. Агент ценен не тем, что собирает информацию, а тем, что превращает её в решение. «Цена изменилась» — это факт. «Цена изменилась, и вот что мы можем сделать» — это уже стратегия.
