Разработка бота-парсера цен конкурентов по расписанию

Ручной мониторинг цен конкурентов отнимает время и приводит к потерям продаж, когда вы узнаёте об изменениях слишком поздно. Мы разрабатываем ботов-парсеров, которые автоматически собирают цены по расписанию, хранят историю и корректируют ваши цены по гибким правилам. Наша команда реализует проект под ключ — от аудита до внедрения и последующей поддержки.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка бота-парсера цен конкурентов по расписанию
Средний
~3-5 дней
Часто задаваемые вопросы

Представьте: ваш конкурент снижает цену на 15% на топ-20 позиций, а вы узнаёте об этом через неделю, когда продажи уже упали. Именно это произошло с одним из наших клиентов, потерявшим 30% маржи за месяц. Чтобы исключить такие ситуации, мы разрабатываем автоматические боты-парсеры цен, которые работают по расписанию, хранят историю и могут самостоятельно корректировать ваши цены по гибким правилам. Мы занимаемся мониторингом цен более 7 лет и реализовали 40+ проектов для e-commerce — от одежды до электроники. Гарантируем корректную работу парсера на всех этапах, от сбора до авторепрайсинга. Свяжитесь с нами, чтобы мы разработали систему под ваш каталог.

Почему ручной мониторинг цен неэффективен?

  • Устаревшие данные: вы проверяете цены раз в неделю, а конкуренты меняют их ежедневно. К моменту вашей реакции вы уже потеряли часть продаж или маржи.
  • Антиблокировочные меры: конкуренты используют Cloudflare, капчи, динамические селекторы. Ручной сбор не справляется, нужен headless-браузер с ротацией прокси.
  • Нормализация: цены приходят в разном формате: с налогом, без налога, в разных валютах, с пробелами и символами. Без нормализации сравнивать их бесполезно.

Как мы строим систему мониторинга?

Мы используем Laravel 11 на PHP 8.3, PostgreSQL для хранения, Redis для очередей и Playwright для парсинга динамики. Архитектура микросервисная — каждый конкурент обрабатывается независимо.

Scheduler → ScrapeCompetitorPrices Job (per competitor) → CompetitorScraper (HTTP/Playwright) → PriceNormalizer → PriceHistoryRepository (INSERT) → PriceChangeDetector → AlertDispatcher (если изменение > порога) → RepricingEngine (если включён autoprice) 

Модель данных

// database/migrations/create_competitor_prices_table.php
Schema::create('competitor_prices', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constrained();
    $table->foreignId('competitor_id')->constrained();
    $table->string('competitor_sku')->nullable();
    $table->string('competitor_url');
    $table->decimal('price', 12, 2);
    $table->decimal('sale_price', 12, 2)->nullable();
    $table->boolean('in_stock')->default(true);
    $table->timestamp('scraped_at');
    $table->timestamps();
    $table->index(['product_id', 'competitor_id', 'scraped_at']);
});

// История для графиков и аналитики
Schema::create('competitor_price_history', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constrained();
    $table->foreignId('competitor_id')->constrained();
    $table->decimal('price', 12, 2);
    $table->boolean('in_stock');
    $table->date('recorded_date');
    $table->timestamps();
    $table->unique(['product_id', 'competitor_id', 'recorded_date']);
});

Конфигурация конкурентов

// config/competitors.php
return [
    'competitor_a' => [
        'name' => 'Shop A',
        'base_url' => 'https://shop-a.ru',
        'selectors' => [
            'price' => '.current-price',
            'in_stock' => '.in-stock-badge',
        ],
        'price_regex' => '/[\d\s]+/',
        'url_pattern' => 'https://shop-a.ru/product/{sku}',
        'requires_js' => false,
        'request_delay' => [1000, 3000], // ms
    ],
    'wildberries' => [
        'name' => 'Wildberries',
        'type' => 'api',
        'scraper' => WildberriesPriceScraper::class,
        'request_delay' => [500, 1500],
    ],
];

Базовый скрапер цен

// app/Services/PriceMonitor/CompetitorPriceScraper.php
class CompetitorPriceScraper
{
    public function __construct(
        private Client $httpClient,
        private array $config
    ) {}

    public function scrapePrice(string $url): ?PriceData
    {
        try {
            $html = $this->fetch($url);
            $crawler = new Crawler($html);

            $priceText = $crawler->filter($this->config['selectors']['price'])
                ->first()
                ->text('');
            $price = $this->extractPrice($priceText);

            if ($price === null) {
                return null;
            }

            $salePrice = null;
            if (!empty($this->config['selectors']['sale_price'])) {
                $salePriceText = $crawler->filter($this->config['selectors']['sale_price'])
                    ->first()->text('');
                $salePrice = $this->extractPrice($salePriceText);
            }

            $inStock = true;
            if (!empty($this->config['selectors']['in_stock'])) {
                $inStock = $crawler->filter($this->config['selectors']['in_stock'])->count() > 0;
            }

            return new PriceData(
                price: $price,
                salePrice: $salePrice,
                inStock: $inStock,
            );
        } catch (\Exception $e) {
            Log::warning("Price scrape failed for {$url}: {$e->getMessage()}");
            return null;
        }
    }

    private function extractPrice(string $text): ?float
    {
        $cleaned = preg_replace('/[^\d,.]/', '', str_replace(' ', '', $text));
        $cleaned = str_replace(',', '.', $cleaned);
        return is_numeric($cleaned) ? (float) $cleaned : null;
    }
}

Job с детектором изменений

// app/Jobs/MonitorCompetitorPrice.php
class MonitorCompetitorPrice implements ShouldQueue
{
    public int $tries = 3;
    public array $backoff = [60, 120, 300];

    public function __construct(
        private int $productId,
        private int $competitorId,
        private string $competitorUrl
    ) {}

    public function handle(
        CompetitorPriceScraper $scraper,
        PriceChangeDetector $detector,
        RepricingEngine $repricer
    ): void {
        $config = Competitor::find($this->competitorId)->config;
        $priceData = $scraper->scrapePrice($this->competitorUrl);

        if ($priceData === null) return;

        // Сохранение текущей цены
        $record = CompetitorPrice::updateOrCreate(
            [
                'product_id' => $this->productId,
                'competitor_id' => $this->competitorId,
            ],
            [
                'price' => $priceData->price,
                'sale_price' => $priceData->salePrice,
                'in_stock' => $priceData->inStock,
                'scraped_at' => now(),
            ]
        );

        // Сохранение в историю (один раз в день)
        CompetitorPriceHistory::firstOrCreate(
            [
                'product_id' => $this->productId,
                'competitor_id' => $this->competitorId,
                'recorded_date' => today(),
            ],
            [
                'price' => $priceData->price,
                'in_stock' => $priceData->inStock,
            ]
        );

        // Детект изменений
        if ($record->wasChanged('price')) {
            $change = $detector->analyze($record);

            if ($change->isSignificant()) {
                Notification::route('mail', config('monitoring.alert_email'))
                    ->notify(new CompetitorPriceChangedNotification($record, $change));
            }

            // Автоперейценка
            if (config('repricing.enabled')) {
                $repricer->recalculate($this->productId);
            }
        }
    }
}

Настройка расписания мониторинга

Расписание настраивается под ваши задачи. Высокоприоритетные товары — каждые 2 часа, массовые — раз в день ночью. Планировщик Laravel предотвращает наложение задач.

Для агрегации истории цен мы запускаем ежедневный артефакт, который сводит данные за день в одну запись — это экономит место и ускоряет запросы графиков.

Автоматический парсер обрабатывает 1000 товаров за 10 минут, что в 40 раз быстрее ручного сбора.

Какие данные сохраняются в истории цен?

Сохраняется цена, цена со скидкой, признак наличия на складе и дата. История ведётся по дням — это позволяет строить графики трендов и анализировать сезонность. Например, вы можете увидеть, что каждую зиму конкурент снижает цены на 10% на определённые категории, и подготовиться заранее.

Стратегии автоматического перейценивания

Стратегия Описание Когда применять
beat_lowest Установить цену на N долларов ниже минимальной Агрессивный захват доли, если есть запас маржи
match_lowest Сравнять с минимальной ценой конкурента Удержание позиций в высококонкурентных нишах
beat_average Цена на N долларов ниже средней цены конкурентов Баланс между маржой и конкурентоспособностью
percentile Цена на заданном перцентиле (например, 25-й) Сохранение позиционирования (премиум или бюджет)

Каждая стратегия учитывает минимальное изменение в 0.5%, чтобы избежать скачков цен.

Дашборд мониторинга

Ключевые метрики для отображения:

Метрика Описание
Товары, где мы дороже Количество и % от каталога
Средняя дельта к минимуму Средний % разницы с lowest price
Товары с изменением > 5% Требуют ручной проверки
Товары вне остатков у конкурентов Потенциал для повышения цены

Дашборд позволяет быстро выявлять аномалии, например, внезапное изменение цены у крупного конкурента.

Типичные ошибки при внедрении мониторинга цен

  • Игнорирование изменения селекторов. Если сайт конкурента меняет вёрстку — парсер падает. Всегда используйте fallback-селекторы и алерты при сбоях.
  • Слишком частые запросы. Защита Cloudflare блокирует IP. Выдерживайте задержки и используйте ротацию прокси.
  • Отсутствие порогов в автоперейценке. Без минимального процента изменения вы будете менять цену на копейки, что раздражает покупателей и теряет доверие.

Что входит в работу

  • Документация: описание архитектуры мониторинга, инструкция по добавлению нового конкурента, настройка правил репрайсинга.
  • Доступы: предоставляем доступ к серверу, очередям, дашборду.
  • Обучение: проводим демо-сессию дашборда и правил для вашей команды.
  • Поддержка: бесплатная поддержка в течение 1 месяца после запуска.

Сроки и стоимость

Разработка базовой системы (1 конкурент + история + алерты) занимает 4–6 рабочих дней. Полная система с автоперейценкой и дашбордом для 5+ конкурентов — 10–14 дней. Стоимость рассчитывается индивидуально, исходя из числа конкурентов, сложности парсинга и требуемых интеграций. Закажите индивидуальную разработку системы мониторинга цен — свяжитесь с нами для оценки вашего проекта.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1543
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1374
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1142
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060