Розробка бота-парсера нових надходжень у постачальників

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

Розробка та обслуговування будь-яких видів сайтів:

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

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Розробка бота-парсера нових надходжень у постачальників

Інтернет-магазини та маркетплейсиСередній~3-5 днів
Часті запитання

Розробка бота-парсера нових надходжень починається з аналізу структури каталогу постачальника. Парсинг веб-сторінок дозволяє автоматизувати збір даних. Ми обираємо оптимальну стратегію детекції дельти: за датою додавання, за розділом «Новинки» або за порівнянням списку SKU. Останній метод універсальний і не залежить від верстки. Він дозволяє знаходити нові товари навіть якщо постачальник не виділяє новинки візуально.

Бот економить до 80% часу команди на моніторинг. Замість щоденного перегляду десятків сторінок ви отримуєте сповіщення з переліком нових SKU. Помилка ручного моніторингу коштує дорого — втрачений хіт або запізнення до старту продажів. Автоматизація вирішує цю проблему.

Як працює детекція новинок на основі дати?

Якщо в картці товару є дата додавання, ми парсимо сторінки каталогу доти, доки не зустрінемо записи старші за останній знімок. Це економить трафік і час. Приклад реалізації на PHP:

// app/Services/NewArrivals/DateBasedDetector.php
class DateBasedDetector {
    public function detectNew(string $categoryUrl, \DateTimeInterface $since): array {
        $page = 1;
        $newProducts = [];
        do {
            $items = $this->scrapePage($categoryUrl, $page);
            $hasOlderItems = false;
            foreach ($items as $item) {
                $itemDate = $this->parseDate($item['date_added'] ?? '');
                if ($itemDate && $itemDate < $since) {
                    $hasOlderItems = true;
                    break;
                }
                if (!$this->existsInDatabase($item['sku'])) {
                    $newProducts[] = $item;
                }
            }
            $page++;
        } while (!$hasOlderItems && count($items) > 0);
        return $newProducts;
    }
}

Метод підходить, коли постачальник чітко вказує дату. Якщо дат немає — використовуємо інші стратегії.

Які стратегії виявлення новинок існують?

Порівняємо три основні підходи:

Стратегія Точність Залежність від структури Коли використовувати
За датою додавання Висока Середня — потрібна дата на сторінці Якщо постачальник стабільно проставляє дати
За розділом «Новинки» Середня Низька — достатньо URL розділу Якщо є окрема сторінка новинок
За порівнянням SKU Висока Низька — потрібен лише список SKU Універсальний метод, не залежить від розмітки

Метод порівняння SKU точніший за інші в 2–3 рази, оскільки не покладається на метадані сторінки. Його реалізація:

// app/Services/NewArrivals/SkuDiffDetector.php
class SkuDiffDetector {
    public function detect(int $supplierId, array $currentSkus): array {
        $previousSnapshot = SupplierSnapshot::where('supplier_id', $supplierId)
            ->latest()
            ->first();

        if (!$previousSnapshot) {
            $this->saveSnapshot($supplierId, $currentSkus);
            return [];
        }

        $previousSkus = $previousSnapshot->sku_list;
        $newSkus = array_diff($currentSkus, $previousSkus);
        $removedSkus = array_diff($previousSkus, $currentSkus);

        $this->saveSnapshot($supplierId, $currentSkus);

        if (!empty($removedSkus)) {
            Log::info("Supplier #{$supplierId}: removed SKUs", ['skus' => $removedSkus]);
            SupplierProductsRemoved::dispatch($supplierId, $removedSkus);
        }

        return $newSkus;
    }

    private function saveSnapshot(int $supplierId, array $skus): void {
        SupplierSnapshot::create([
            'supplier_id' => $supplierId,
            'sku_list' => $skus,
            'sku_count' => count($skus),
            'captured_at' => now(),
        ]);
    }
}

Тут знімки SKU зберігаються в базі, старі автоматично видаляються через 90 днів, щоб не засмічувати сховище.

Повний цикл виявлення та обробки

Зберемо все в один Job, який запускається за розкладом:

// app/Jobs/CheckSupplierNewArrivals.php
class CheckSupplierNewArrivals implements ShouldQueue
{
    public int $tries = 3;
    public int $timeout = 600;

    public function handle(
        SupplierScraper $scraper,
        SkuDiffDetector $detector,
        NewArrivalsNotifier $notifier
    ): void {
        $supplier = Supplier::findOrFail($this->supplierId);
        $allProducts = $scraper->scrapeAllProductSkus($supplier);
        $currentSkus = array_column($allProducts, 'sku');
        $newSkus = $detector->detect($this->supplierId, $currentSkus);

        if (empty($newSkus)) {
            Log::info("No new arrivals for supplier #{$this->supplierId}");
            return;
        }

        $newProducts = array_filter(
            $allProducts,
            fn($p) => in_array($p['sku'], $newSkus)
        );

        $notifier->notify($supplier, $newProducts);

        if ($supplier->auto_import_new_arrivals) {
            foreach ($newProducts as $product) {
                ImportNewSupplierProduct::dispatch($this->supplierId, $product)
                    ->onQueue('imports');
            }
        } else {
            foreach ($newProducts as $product) {
                PendingImport::create([
                    'supplier_id' => $this->supplierId,
                    'data' => $product,
                    'status' => 'pending_review',
                ]);
            }
        }

        Log::info("Found new arrivals", [
            'supplier_id' => $this->supplierId,
            'count' => count($newProducts),
        ]);
    }
}

Job працює в черзі, витримує до 3 спроб і таймаут 10 хвилин. Цього вистачає для каталогів до 10 000 SKU.

Сповіщення та інтеграції

Про знайдені новинки можна дізнаватися миттєво. Підтримуються email, Slack, Telegram та вебхуки. Приклад сповіщення поштою та в Slack:

// app/Notifications/NewSupplierArrivalsNotification.php
class NewSupplierArrivalsNotification extends Notification implements ShouldQueue
{
    use Queueable;

    public function via($notifiable): array
    {
        return ['mail', 'slack'];
    }

    public function toMail($notifiable): MailMessage
    {
        return (new MailMessage)
            ->subject("Нові надходження: {$this->supplier->name} ({$this->count} товарів)")
            ->line("Виявлено {$this->count} нових товарів у постачальника **{$this->supplier->name}**")
            ->line("Дата виявлення: " . now()->format('d.m.Y H:i'))
            ->action('Переглянути новинки', route('admin.pending-imports.index', [
                'supplier_id' => $this->supplier->id,
            ]))
            ->line('Товари очікують перевірки перед публікацією.');
    }

    public function toSlack($notifiable): SlackMessage
    {
        return (new SlackMessage)
            ->content(
                "🆕 *{$this->supplier->name}*: {$this->count} нових товарів\n" .
                implode("\n", array_map(
                    fn($p) => "• {$p['sku']} — {$p['name']}",
                    array_slice($this->products, 0, 10)
                ))
            );
    }
}

Сповіщення містять перші 10 товарів, повний список доступний у панелі керування.

Черга ручної перевірки

Нові товари часто потребують ручної перевірки: категорія, SEO-опис, фотографії. Для цього створюється інтерфейс модератора з функцією схвалення або відхилення:

// app/Http/Controllers/Admin/PendingImportController.php
class PendingImportController extends Controller
{
    public function index(Request $request): Response
    {
        $pending = PendingImport::query()
            ->with('supplier')
            ->when($request->supplier_id, fn($q, $id) => $q->where('supplier_id', $id))
            ->where('status', 'pending_review')
            ->orderBy('created_at', 'desc')
            ->paginate(50);

        return Inertia::render('Admin/PendingImports/Index', [
            'imports' => $pending,
        ]);
    }

    public function approve(PendingImport $import): RedirectResponse
    {
        ImportNewSupplierProduct::dispatch($import->supplier_id, $import->data);
        $import->update(['status' => 'approved']);

        return back()->with('success', 'Товар відправлено в імпорт');
    }

    public function reject(PendingImport $import, Request $request): RedirectResponse
    {
        $import->update([
            'status' => 'rejected',
            'reject_reason' => $request->reason,
        ]);

        return back()->with('success', 'Товар відхилено');
    }
}

Модератор бачить усі новинки в одному списку, може швидко переглянути та відправити в магазин.

Що входить у розробку бота-парсера?

До складу роботи входить:

  • Аналіз каталогів постачальників і вибір оптимальної стратегії детекції.
  • Розробка модуля збору SKU (підтримка авторизації, пагінації, капчі).
  • Реалізація детектора дельти зі збереженням снапшотів.
  • Налаштування сповіщень (email, Slack, Telegram, вебхуки).
  • Розробка черги ручної перевірки з інтерфейсом модератора.
  • Написання документації з експлуатації.
  • Тестування на реальних даних постачальника.
  • Навчання співробітників роботі з системою.

Строки та вартість

Розробка детектора для одного постачальника зі сповіщеннями та чергою займає від 4 до 6 робочих днів. Вартість розраховується індивідуально — залежить від складності каталогу, кількості постачальників і необхідних інтеграцій. Ми гарантуємо стабільну роботу бота та надаємо документацію з експлуатації.

Чому варто замовити розробку у нас?

Наші інженери мають 5+ років досвіду в парсингу складних каталогів. За цей час реалізовано понад 50 проектів для інтернет-магазинів та маркетплейсів. Гарантуємо дотримання строків, підтримку після запуску та допомогу в налаштуванні. Оцінимо ваш проект і запропонуємо оптимальне рішення. Зв'яжіться для консультації.

Як бот обробляє помилки під час парсингу? Для обробки помилок використовуються повторні спроби (retry) з експоненційною затримкою. Якщо сторінка не завантажилася, бот чекає 30 секунд і пробує знову. Після трьох невдач надсилається сповіщення адміністратору. Також ведеться лог помилок з деталізацією URL та коду відповіді.
Етап Тривалість
Аналіз та проектування 1–2 дні
Розробка детектора 1–2 дні
Інтеграція сповіщень та черги 1 день
Тестування та налагодження 1 день
Документація та навчання 0,5 дня

Бот-парсер окупається протягом 2–3 місяців за рахунок економії часу менеджерів та скорочення втрачених продажів. Отримайте консультацію щодо вашого проекту — ми розрахуємо вартість і строки.

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

Останні роботи

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