Обновлять страницу товара и копировать числа в таблицу работает до тех пор, пока вы отслеживаете больше нескольких позиций. Это медленно, легко упустить, и, что хуже, это говорит вам, какова цена прямо сейчас, но ничего о том, изменилась ли она, насколько, и имеет ли это значение. Интересный сигнал в данных о товарах, это изменение, а не снимок, и увидеть изменение можно только при регулярном сборе одних и тех же полей и их сравнении во времени.
Это руководство создаёт небольшой, работающий инструмент мониторинга товаров с ИИ на Python. Он парсит публичные страницы товаров по таймеру с помощью Crawlbase, сохраняет каждое значение, сравнивает новое с предыдущим для обнаружения существенных изменений цены, наличия и рейтинга, а затем передаёт эти изменения LLM, который составляет краткое оповещение на понятном языке. Всё здесь ограничено публичными данными о товарах: ценами, наличием и рейтингами, которые любой посетитель видит без авторизации. Никаких аккаунтов, корзин, персональных данных.
Что делает инструмент от начала до конца
Представьте систему как эстафету из четырёх станций. Сначала Crawlbase получает страницу товара и возвращает чистые структурированные поля, чтобы вам не пришлось самостоятельно парсить хрупкий HTML. Затем каждое значение записывается в локальное хранилище с временной меткой, которая формирует историю, необходимую для обнаружения изменений. Далее шаг сравнения сопоставляет последнее значение с предыдущим и решает, изменилось ли что-то существенно. Наконец, при реальном изменении LLM превращает сырые данные «до/после» в однострочное резюме, которое можно отправить в Slack, по email или в журнал.
Цикл планирования оборачивает все четыре станции, и всё работает само по себе, раз в час или раз в день, без вашего наблюдения. Именно этот цикл превращает разовый парсинг в настоящий мониторинг. Та же структура лежит в основе большинства задач веб-парсинга в eCommerce: собрать, сохранить, сравнить, действовать.
Предварительные требования
Экспертный уровень не нужен, но небольшая подготовка помогает. Вы должны уметь читать и редактировать скрипт на Python, отправлять HTTP-запрос и проверять возвращаемый JSON, а также запускать файл из терминала. Общее понимание того, как LLM реагирует на структурированный промпт, полезно для шага резюмирования, хотя код берёт на себя всю интеграцию.
На стороне инструментов нужны три вещи: Python 3.9 или новее, установленный локально, аккаунт Crawlbase с токеном API и ключ API для LLM, который вы используете для шага резюмирования (в примере используется эндпоинт, совместимый с OpenAI, его предоставляют большинство провайдеров). Новые аккаунты Crawlbase дают до 20 000 бесплатных запросов: 1 000 при регистрации и больше по мере прохождения шагов онбординга, вполне достаточно для создания и тестирования на нескольких реальных товарах.
Настройка проекта
Создайте папку, виртуальное окружение и установите две библиотеки, на которые опирается инструмент: клиент Crawlbase для парсинга и клиент openai для шага резюмирования (он работает с любым OpenAI-совместимым API).
python --version mkdir product-monitor && cd product-monitor python -m venv .venv source .venv/bin/activate pip install crawlbase openai
Держите оба ключа вне кода. Читайте их из переменных окружения, чтобы ничего секретного не попало в коммит. Установите их один раз в своей оболочке перед запуском.
export CRAWLBASE_TOKEN="your_crawlbase_token" export LLM_API_KEY="your_llm_api_key"
Шаг 1: Сбор данных о товаре через Crawlbase
Первая станция получает страницу товара и возвращает интересующие нас поля. Самый чистый путь для поддерживаемых магазинов, Crawling API, который запускает поддерживаемый парсер на стороне сервера и возвращает структурированный JSON вместо сырого HTML. Вы вызываете тот же эндпоинт, что и Crawling API, и добавляете параметр scraper с именем нужного парсера. Сохраните это как collect.py.
import os from crawlbase import ScraperAPI scraper = ScraperAPI({"token": os.environ["CRAWLBASE_TOKEN"]}) def collect_product(url): # 'amazon-product-details' is one of the maintained parsers. response = scraper.get(url, {"scraper": "amazon-product-details"}) body = response["json"]["body"] reading = { "url": url, "name": body.get("name"), "price": body.get("rawPrice"), "currency": body.get("currency"), "in_stock": body.get("inStock"), "rating": body.get("rating"), } if reading["price"] is None or reading["name"] is None: raise ValueError(f"Parse returned no price/name for {url}") return reading
Если отслеживаемый магазин не является одним из поддерживаемых парсеров, опуститесь до Crawling API и парсите HTML самостоятельно, либо создайте специфический для цели экстрактор. В любом случае Crawlbase берёт на себя сложную часть запроса: ротирует IP, управляет заголовками и рендерит JavaScript при необходимости, так что вы получаете реальный ответ вместо страницы блокировки.
Scraper API и Crawling API по умолчанию выполняют быстрый статичный запрос. Если страница товара рендерит цену или наличие на стороне клиента (что типично для современных магазинов), передайте "ajax_wait": "true" и "page_wait" в миллисекундах, чтобы контент загрузился до возврата HTML. Начните с 5000 мс и увеличивайте, если поле возвращается пустым.
Шаг 2: Сохранение каждого значения с временной меткой
Обнаружение изменений требует памяти, поэтому каждое значение записывается на диск с временем снятия. Одного файла SQLite достаточно и сохраняет инструмент минимально зависимым. Сохраните это как store.py.
import sqlite3 from datetime import datetime, timezone DB = "readings.db" def init_db(): con = sqlite3.connect(DB) con.execute( """CREATE TABLE IF NOT EXISTS readings ( url TEXT, name TEXT, price REAL, currency TEXT, in_stock INTEGER, rating REAL, taken_at TEXT)""" ) con.commit() con.close() def save_reading(r): con = sqlite3.connect(DB) con.execute( "INSERT INTO readings VALUES (?, ?, ?, ?, ?, ?, ?)", (r["url"], r["name"], r["price"], r["currency"], int(bool(r["in_stock"])), r["rating"], datetime.now(timezone.utc).isoformat()), ) con.commit() con.close() def last_two(url): con = sqlite3.connect(DB) con.row_factory = sqlite3.Row rows = con.execute( "SELECT * FROM readings WHERE url = ? ORDER BY taken_at DESC LIMIT 2", (url,), ).fetchall() con.close() return [dict(row) for row in rows]
last_two возвращает самое свежее значение и предыдущее, именно это нужно шагу сравнения. Если вы позднее захотите получить полную историю цен для построения графика, таблица уже содержит каждую строку; просто выберите все по URL в порядке taken_at.
Шаг 3: Обнаружение существенных изменений
Именно здесь большинство наивных мониторов ошибаются: они сигнализируют о каждом малейшем колебании, поэтому вы перестаёте их замечать в течение дня. Решение, порог. Считайте изменение цены значимым только при пересечении установленного процента, и всегда сигнализируйте о бинарных событиях, например, когда товар заканчивается. Сохраните это как detect.py.
PRICE_THRESHOLD = 0.03 # 3% move counts as meaningful def detect_changes(current, previous): changes = [] old_price, new_price = previous["price"], current["price"] if old_price and new_price: delta = (new_price - old_price) / old_price if abs(delta) >= PRICE_THRESHOLD: changes.append({ "field": "price", "old": old_price, "new": new_price, "pct": round(delta * 100, 1), }) if previous["in_stock"] != current["in_stock"]: changes.append({ "field": "in_stock", "old": bool(previous["in_stock"]), "new": bool(current["in_stock"]), }) if previous["rating"] and current["rating"]: if abs(current["rating"] - previous["rating"]) >= 0.2: changes.append({ "field": "rating", "old": previous["rating"], "new": current["rating"], }) return changes
Настраивайте пороги под конкретный товар. Commodity, которая колышется на несколько центов весь день, требует более широкого ценового диапазона; дорогостоящий товар, для которого падение на 3%, реальные деньги, требует более узкого. Смысл в том, что правило находится в понятном коде, который вы можете читать и корректировать, а не в скрытой логике модели.
Монитор надёжен ровно настолько, насколько надёжны питающие его данные. Scraper API возвращает чистые структурированные поля товаров из поддерживаемых магазинов, с ротацией IP, управлением заголовками и рендерингом JavaScript на стороне сервера, так что запланированное задание продолжает возвращать реальные значения вместо страниц блокировки. Направьте его на публичную страницу товара на бесплатном тарифе и постройте цикл вокруг него.
Шаг 4: Резюмирование и оповещение через LLM
Список словарей с изменениями корректен, но не читается с первого взгляда. Задача LLM здесь узкая, и это намеренно: превратить структурированные изменения в одно короткое, точное предложение. Удерживая модель на строгом, структурированном вводе, мы не даём ей отклоняться или изобретать детали. Сохраните это как alert.py.
import os import json from openai import OpenAI client = OpenAI(api_key=os.environ["LLM_API_KEY"]) def summarize_changes(product_name, changes): prompt = ( f"Product: {product_name}\n" f"Detected changes (JSON): {json.dumps(changes)}\n\n" "Write one short sentence summarizing what changed. " "State only what the data shows. Do not speculate or " "add numbers that are not present." ) response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You summarize product data changes factually."}, {"role": "user", "content": prompt}, ], temperature=0.1, ) return response.choices[0].message.content.strip() def send_alert(message): # Swap this for Slack, email, or a webhook in production. print(f"[ALERT] {message}")
Низкая temperature и инструкция сообщать только то, что показывают данные, удерживают резюме привязанным к переданным числам. Если вы предпочитаете не зависеть от размещённой модели, направьте тот же вызов через самостоятельно размещённый или альтернативный эндпоинт, совместимый с OpenAI, изменив базовый URL клиента; остальная часть функции остаётся неизменной. Для реальной доставки оповещения замените print в send_alert на отправку через Slack webhook или email.
Шаг 5: Объединение цикла
Теперь соедините четыре станции в один проход по вашему списку наблюдения. Каждый запуск собирает свежее значение, сохраняет его, сравнивает с предыдущим и отправляет оповещение только при обнаружении отличия. Сохраните это как monitor.py.
from collect import collect_product from store import init_db, save_reading, last_two from detect import detect_changes from alert import summarize_changes, send_alert WATCHLIST = [ "https://www.example-store.com/product/abc", "https://www.example-store.com/product/xyz", ] def run_once(): init_db() for url in WATCHLIST: try: reading = collect_product(url) except Exception as exc: print(f"Skipped {url}: {exc}") continue save_reading(reading) history = last_two(url) if len(history) < 2: continue # first reading, nothing to compare current, previous = history[0], history[1] changes = detect_changes(current, previous) if changes: summary = summarize_changes(reading["name"], changes) send_alert(summary) if __name__ == "__main__": run_once()
Запустите дважды с промежутком (или заполните таблицу двумя значениями), и вы увидите, как оповещение срабатывает при изменении чего-либо. Единственный проход по стабильному товару ничего не печатает, и это именно то, что нужно: тишина, если нет новостей.
python monitor.py # [ALERT] The price of "Acme Widget" dropped 7.4% from $129 to $119, and it is back in stock.
Шаг 6: Планирование запуска
Мониторинг означает запуск по таймеру без ввода команды вручную. Не создавайте бесконечный цикл внутри Python-процесса с вызовом sleep; он умирает при перезагрузке машины и не оставляет журналов. Передайте расписание операционной системе. На Linux или macOS запись cron для запуска скрипта каждый час выглядит следующим образом.
# crontab -e, then add (runs at the top of every hour): 0 * * * * cd /path/to/product-monitor && .venv/bin/python monitor.py >> monitor.log 2>&1
В Windows Task Scheduler выполняет ту же задачу: направьте базовое задание на исполняемый файл Python внутри виртуального окружения с аргументом monitor.py и установите нужный интервал. В любом случае выбирайте периодичность, соответствующую скорости изменения данных. Ежечасно подходит для быстро меняющихся цен; раз в день достаточно для наличия и рейтингов и более экономно с точки зрения расхода запросов.
По мере роста списка наблюдения сверх нескольких товаров синхронный цикл, получающий один URL за раз, начинает замедляться. В этот момент перенесите сбор на асинхронный Crawler, который отправляет результаты на webhook по мере готовности страниц, чтобы вы не блокировались на каждом запросе. Более широкая стратегия отслеживания цен конкурентов во времени описана в статье об использовании веб-парсинга для ценовой аналитики; то, как та же конвейерная линия выдерживает нагрузку в масштабе, разобрано в статье о крупномасштабном парсинге eCommerce.
Поддержание потока данных
Запланированный скрапер, это скрапер, который должен продолжать работать без надзора, поэтому надёжность важнее всего на уровне данных. Crawlbase уже ротирует IP и управляет заголовками в каждом запросе, что не даёт повторяющемуся заданию помечаться как бот. Если вам нужен более тонкий контроль над маршрутизацией или вы хотите отправлять собственный HTTP-клиент через ротируемый пул, Smart AI Proxy предоставляет ту же сеть как стандартный прокси-эндпоинт. Следите в журналах запусков за кодами статуса, отклоняющимися от успеха: внезапная серия запросов на верификацию или ошибок, сигнал снизить периодичность или расширить ротацию, а не повторять упорнее.
Ключевые выводы
- Мониторьте изменение, а не снимок. Ценность в сравнении значений во времени, а значит, нужно сохранять каждое значение с временной меткой.
- Crawlbase, надёжный уровень данных. Crawling API возвращает чистые структурированные поля, а ротация IP и рендеринг не дают запланированному заданию блокироваться.
- Используйте порог для обнаружения существенных изменений. Процентный диапазон по цене плюс бинарные проверки наличия превращают оповещения в сигнал, а не шум.
- Держите LLM в узких рамках. Передавайте ему структурированное сравнение, просите об одном фактическом предложении при низкой температуре, и он резюмирует вместо того, чтобы изобретать.
- Пусть ОС планирует.. Cron или Task Scheduler лучше, чем встроенный в процесс sleep-цикл; выбирайте периодичность, соответствующую скорости изменения данных.
- Оставайтесь на публичных данных. Только цены, наличие и рейтинги; никаких аккаунтов, корзин или персональных данных.
Часто задаваемые вопросы
Что такое инструмент мониторинга товаров с ИИ?
Это программа, которая отслеживает публичные страницы товаров по расписанию, каждый раз записывает ключевые поля вроде цены, наличия и рейтинга, и использует модель ИИ для выявления и объяснения существенных изменений. Уровень парсинга обеспечивает надёжный поток данных, а уровень ИИ превращает сырые данные «до/после» в краткое читаемое оповещение, чтобы вы действовали на основе того, что изменилось, а не читали таблицы.
Нужен ли Crawling API или Scraper API для этого?
Используйте Scraper API, когда отслеживаемый магазин является одним из поддерживаемых парсеров, поскольку он напрямую возвращает структурированные поля товара и избавляет от написания кода извлечения. Используйте Crawling API, когда вам нужен сырой HTML для самостоятельного парсинга или страница не покрыта парсером. Оба используют одну сеть, поэтому ротация IP и рендеринг работают в любом случае; разница лишь в том, разбирает ли Crawlbase страницу за вас.
Как инструмент решает, что является существенным изменением?
По порогам, которые вы задаёте в понятном коде, а не по логике модели. В примере изменение цены считается существенным только при пересечении процентного диапазона (3% по умолчанию), товар, уходящий из наличия или возвращающийся в него, всегда помечается, а сдвиг рейтинга на 0.2 и более, тоже. Ужесточение или ослабление этих чисел для конкретного товара, способ поддерживать полезность оповещений, а не их постоянство.
Будет ли ИИ галлюцинировать числа при составлении оповещения?
Такой риск есть при открытых промптах, именно поэтому шаг резюмирования держится в узких рамках. Модель получает только структурированное сравнение, работает при низкой температуре и получает инструкцию сообщать только то, что показывают данные, и не добавлять числа, которых нет. Именно эта структура удерживает предложение привязанным к реальным значениям, а не к придуманным деталям.
Что происходит при изменении макета страницы в магазине?
Если вы используете Crawling API, поддерживаемый парсер поглощает большинство изменений макета за вас, это одна из причин его использования при возможности. Если вы парсите HTML самостоятельно через Crawling API, изменение макета может сломать ваши селекторы, и исправление состоит в повторной проверке живой страницы и их обновлении. Поскольку Crawlbase всегда возвращает полную страницу, вы корректируете логику парсинга, а не перестраиваете запрос.
Как часто должен запускаться монитор?
Подбирайте периодичность под скорость изменения данных и ваш бюджет запросов. Ежечасно подходит для быстро меняющихся цен; раз в день достаточно для наличия и рейтингов и расходует значительно меньше запросов. Планирование через cron или Windows Task Scheduler позволяет устанавливать интервал для каждого задания, и вы можете запускать разные товары с разной частотой, если некоторые важнее других.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

