Бот-парсер товаров поставщиков: автоматический сбор данных

Менеджеры тратят до 3 часов в день на копирование данных из кабинетов поставщиков. При ручном вводе ошибки достигают 15%, а устаревшие цены ведут к прямым убыткам. Результат — потерянные сделки и недовольные клиенты. Мы автоматизируем сбор товаров, цен и остатков без участия человека. За время работ

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Бот-парсер товаров поставщиков: автоматический сбор данных
Средний
~5 дней

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

Часто задаваемые вопросы

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

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1422
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    984
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1249
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    986
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    1000

Менеджеры тратят до 3 часов в день на копирование данных из кабинетов поставщиков. При ручном вводе ошибки достигают 15%, а устаревшие цены ведут к прямым убыткам. Результат — потерянные сделки и недовольные клиенты. Мы автоматизируем сбор товаров, цен и остатков без участия человека. За время работы на рынке реализовали 30+ проектов, сократив время сбора данных для клиентов на 80%. Например, интернет-магазин с ассортиментом 5000 товаров ежемесячно тратил 40 часов на обновление цен; после внедрения парсера процесс занимает 4 часа автономно. Экономия бюджета — до 30%, что в денежном эквиваленте может составлять, например, 240 000 рублей в год.

Согласно определению, веб-скрапинг — это автоматический сбор данных из интернета. Ниже — как это работает на практике.

Почему ручной сбор данных — это дорого?

80% времени уходит на монотонные операции. Ошибки в 15% записей из-за человеческого фактора. Потеря клиентов из-за неактуальных цен или отсутствия товара на складе. Автоматизация снижает затраты на 30% и полностью исключает ошибки ввода.

Какие данные мы собираем

Тип данных Пример Источник
Основные поля Название, цена, SKU Страница списка товаров
Расширенные Описание, характеристики, изображения Карточка товара
Динамические Остатки, статус наличия AJAX-запросы или DOM

Как работает парсер и как мы обходим защиту?

Архитектура типового решения:

  1. Планировщик (cron / Laravel Horizon) запускает задачи по расписанию.
  2. HTTP-клиент (Guzzle / Playwright) загружает страницы поставщика.
  3. Парсер извлекает данные через CSS-селекторы или XPath.
  4. Нормализатор приводит цены, даты и валюты к единому формату.
  5. Дедупликатор проверяет товар по SKU и обновляет или создаёт запись.
  6. Уведомления при ошибках или значительных изменениях цен.

Современные поставщики используют Cloudflare, капчи и динамическую загрузку. Мы применяем ротацию резидентских прокси, эмуляцию браузера Playwright/Puppeteer со случайными движениями мыши, задержки от 500 мс до 2 с и смену User-Agent. Если сайт использует JavaScript, Playwright загружает страницу как настоящий браузер и возвращает готовый DOM.

Что лучше: Guzzle или Playwright?

Критерий Guzzle (PHP) Playwright (Node)
Скорость Высокая (нет браузера) Средняя (запуск браузера)
Работа с JS Не поддерживает Полная эмуляция
Ресурсы Минимальные Требует больше ОЗУ
Сложность парсинга Достаточно для статики Необходим для SPA

Guzzle обрабатывает статические страницы в 2 раза быстрее Playwright. Комбинированный подход — Guzzle для статики, Playwright для SPA — даёт лучший результат.

Техническая реализация

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

// app/Services/Scrapers/SupplierScraper.php use GuzzleHttp\Client; use Symfony\Component\DomCrawler\Crawler; class SupplierScraper { private Client $client; public function __construct( private string $baseUrl, private array $proxyPool = [] ) { $this->client = new Client([ 'timeout' => 15, 'connect_timeout' => 5, 'headers' => [ 'User-Agent' => $this->randomUserAgent(), 'Accept-Language' => 'ru-RU,ru;q=0.9', 'Accept' => 'text/html,application/xhtml+xml', ], ]); } public function scrapeProductList(string $categoryUrl): array { $html = $this->fetchWithRetry($categoryUrl); $crawler = new Crawler($html); return $crawler->filter('.product-card')->each(function (Crawler $node) { return [ 'url' => $node->filter('a.product-link')->attr('href'), 'title' => trim($node->filter('.product-title')->text()), 'price' => $this->parsePrice($node->filter('.price')->text()), 'sku' => $node->filter('[data-sku]')->attr('data-sku'), ]; }); } public function scrapeProductDetail(string $productUrl): array { $html = $this->fetchWithRetry($this->baseUrl . $productUrl); $crawler = new Crawler($html); return [ 'title' => $crawler->filter('h1.product-name')->text(), 'description' => $crawler->filter('.description')->html(), 'price' => $this->parsePrice($crawler->filter('.current-price')->text()), 'images' => $crawler->filter('.gallery img')->each( fn(Crawler $img) => $img->attr('src') ), 'specs' => $this->extractSpecs($crawler), 'in_stock' => $crawler->filter('.in-stock')->count() > 0, 'sku' => $crawler->filter('[itemprop="sku"]')->text(''), ]; } private function extractSpecs(Crawler $crawler): array { $specs = []; $crawler->filter('.specs-table tr')->each(function (Crawler $row) use (&$specs) { $key = trim($row->filter('td:first-child')->text('')); $val = trim($row->filter('td:last-child')->text('')); if ($key && $val) { $specs[$key] = $val; } }); return $specs; } private function fetchWithRetry(string $url, int $attempts = 3): string { $proxy = $this->proxyPool ? $this->randomProxy() : null; for ($i = 0; $i < $attempts; $i++) { try { $options = $proxy ? ['proxy' => $proxy] : []; $response = $this->client->get($url, $options); return (string) $response->getBody(); } catch (\Exception $e) { if ($i === $attempts - 1) throw $e; sleep(rand(2, 5)); } } } private function parsePrice(string $text): float { return (float) preg_replace('/[^\d.,]/', '', str_replace(',', '.', $text)); } private function randomUserAgent(): string { $agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15', ]; return $agents[array_rand($agents)]; } } 

Job для фоновой обработки

// app/Jobs/ScrapeSupplierProducts.php class ScrapeSupplierProducts implements ShouldQueue { use Queueable; public int $tries = 2; public int $timeout = 300; public function __construct( private int $supplierId, private string $categoryUrl ) {} public function handle( SupplierScraper $scraper, ProductImportService $importer ): void { $products = $scraper->scrapeProductList($this->categoryUrl); foreach ($products as $productPreview) { ScrapeSupplierProductDetail::dispatch( $this->supplierId, $productPreview['url'] )->onQueue('scraper-detail'); usleep(rand(500000, 1500000)); } } } 

Playwright для JS-сайтов

// scraper/playwright-worker.js const { chromium } = require('playwright'); async function scrapeProduct(url) { const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...', viewport: { width: 1366, height: 768 }, }); const page = await context.newPage(); await page.goto(url, { waitUntil: 'networkidle' }); const product = await page.evaluate(() => ({ title: document.querySelector('h1')?.textContent, price: document.querySelector('.price')?.textContent, images: [...document.querySelectorAll('.gallery img')].map(i => i.src), })); await browser.close(); return product; } 

PHP вызывает Node-процесс через proc_open или HTTP-микросервис.

Дедупликация и обновление

// app/Services/ProductImportService.php class ProductImportService { public function upsert(int $supplierId, array $data): void { $product = SupplierProduct::updateOrCreate( [ 'supplier_id' => $supplierId, 'supplier_sku' => $data['sku'], ], [ 'title' => $data['title'], 'price' => $data['price'], 'in_stock' => $data['in_stock'], 'description' => $data['description'], 'images' => json_encode($data['images']), 'specs' => json_encode($data['specs']), 'scraped_at' => now(), ] ); if ($product->wasChanged('price')) { $change = abs($product->price - $product->getOriginal('price')); if ($change / $product->getOriginal('price') > 0.05) { PriceChangedNotification::dispatch($product); } } } } 

Расписание запусков

// app/Console/Kernel.php protected function schedule(Schedule $schedule): void { $schedule->command('scraper:supplier --supplier=1') ->dailyAt('03:00') ->withoutOverlapping(); $schedule->command('scraper:supplier --supplier=1 --prices-only') ->everyFourHours() ->withoutOverlapping(); } 
Пример структуры данных для парсинга
Поле Тип Пример
sku string ART-12345
title string Смартфон XYZ
price float 19999.99
in_stock bool true

Процесс разработки и сроки

  1. Аналитика (1-2 дня) — изучаем структуру сайта поставщика, определяем типы защиты, согласуем поля.
  2. Проектирование (1 день) — выбираем стек, проектируем архитектуру (очереди, расписание, схема данных).
  3. Реализация (3-7 дней) — пишем парсеры, нормализаторы, дедупликацию, интеграцию с вашей системой.
  4. Тестирование (1-2 дня) — прогоняем на реальных данных, проверяем корректность и устойчивость.
  5. Деплой (1 день) — настраиваем окружение, мониторинг, уведомления, передаём документацию.

Сроки ориентировочно

  • Базовый парсер одного поставщика (статический HTML, 5-10 полей): от 3 до 5 рабочих дней.
  • Парсер со сложной защитой или JS-рендерингом: от 7 до 14 дней.
  • Интеграция с несколькими поставщиками в единый pipeline: от 10 рабочих дней.

Стоимость рассчитывается индивидуально после аудита целевых сайтов.

Что входит в результат

  • Парсер с открытым исходным кодом (PHP + Laravel или Node.js).
  • Интеграция с вашей БД через API или прямой импорт.
  • Настройка расписания и мониторинга.
  • Документация по запуску и поддержке.
  • Гарантия стабильной работы 30 дней.

Типичные ошибки при разработке парсеров

  • Игнорирование rate limit — сайт блокирует IP после 100 запросов. Решение: добавлять случайные задержки и ротацию.
  • Жёсткая привязка к структуре HTML — малейшее изменение дизайна ломает парсер. Решение: использовать data-атрибуты или XPath.
  • Отсутствие обработки ошибок — при сбое одного поставщика падает вся очередь. Решение: изолировать задачи и добавить повторные попытки.
  • Сбор всех данных в одну таблицу без нормализации — дубли и пробелы. Решение: использовать SKU как уникальный ключ.

Свяжитесь с нами для консультации — оценим ваш проект и предложим решение под ключ. Закажите разработку парсера и получите готовое решение, которое сэкономит ваше время и деньги.