Автоматизация мониторинга цен на маркетплейсах: от API до Playwright

Когда ручной мониторинг убивает бюджет

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Автоматизация мониторинга цен на маркетплейсах: от API до Playwright
Сложный
~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

Когда ручной мониторинг убивает бюджет

Ваш магазин на Wildberries теряет до 30% выручки из-за неактуальных цен конкурентов? Ручная проверка 15 000 товаров — это 5 человеко-дней в неделю, а ошибка в цене может стоить десятков тысяч рублей. Каждая опоздавшая реакция на изменение цены конкурента — потеря до 50 000 ₽ за час пик. Мы, команда с 5-летним опытом и 40+ успешными проектами по парсингу, знаем, как автоматизировать этот процесс без риска блокировки. Предлагаем решение под ключ: от анализа до интеграции с вашей CRM.

В этой статье разберём три стратегии сбора данных с маркетплейсов: использование официальных API, парсинг публичных JSON-эндпоинтов и браузерная автоматизация с обходом Cloudflare. Вы получите готовые куски кода для Wildberries, Ozon и Amazon, а также чек-лист антидетект-мер, которые гарантируют стабильную работу.

Законные API vs парсинг: что выбрать

Прежде чем писать скрейпер, изучите официальные возможности. API дают структурированные данные, но ограничены вашими товарами. Для конкурентного анализа придётся парсить.

Маркетплейс Официальный API Ограничения
Ozon Seller API (для продавцов) Только свои товары
Wildberries Seller API, Statistics API Только свои данные
Amazon Product Advertising API Требует партнёрство
Яндекс.Маркет Партнёрский API Для партнёров

Парсинг чужих товаров — серая зона ToS. Мы используем его исключительно для конкурентного анализа, мониторинга цен и исследования рынка. Легальные API — база, парсинг — расширение.

Как обойти защиту Cloudflare на Ozon?

Ozon строит страницы на React, данные передаются через XHR-запросы. Cloudflare проверяет JavaScript-окружение, поэтому обычный requests не сработает. Наше решение — Playwright с эмуляцией реального браузера, перехватом API-ответов и ротацией User-Agent. Вот пример парсера:

# scraper/ozon.py from playwright.async_api import async_playwright import json class OzonScraper: async def scrape_product(self, url: str) -> dict: async with async_playwright() as p: browser = await p.chromium.launch(headless=True) context = await browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)", viewport={"width": 1366, "height": 768}, ) # Перехватываем API-ответы с данными товара product_data = {} async def handle_response(response): if "/api/entrypoint-api.bx/page/json" in response.url: try: data = await response.json() widget_states = data.get("widgetStates", {}) for key, value in widget_states.items(): if "webProductHeading" in key: product_data["heading"] = json.loads(value) elif "webPrice" in key: product_data["price"] = json.loads(value) except Exception: pass context.on("response", handle_response) page = await context.new_page() await page.goto(url, wait_until="networkidle") await browser.close() return self._normalize_ozon(product_data) def _normalize_ozon(self, data: dict) -> dict: heading = data.get("heading", {}) price = data.get("price", {}) return { "name": heading.get("title"), "sku": heading.get("sku"), "price": self._parse_price(price.get("price", "")), "original_price": self._parse_price(price.get("originalPrice", "")), "discount": price.get("discount"), } def _parse_price(self, s: str) -> float: return float("".join(c for c in s if c.isdigit() or c == ".") or 0) 

Playwright в 3 раза стабильнее Selenium на динамических сайтах благодаря встроенным ожиданиям и поддержке современных браузеров. Для дополнительной защиты мы используем playwright-stealth — плагин, который маскирует автоматизацию.

Почему Wildberries удобнее для парсинга?

Wildberries имеет публичные JSON API, которые не требуют авторизации. Они работают напрямую, без JavaScript, что упрощает сбор данных. Пример парсера на httpx и asyncio:

# scraper/wildberries.py import httpx import asyncio from typing import Optional class WildberriesScraper: CARD_URL = "https://card.wb.ru/cards/v2/detail" SEARCH_URL = "https://search.wb.ru/exactmatch/ru/common/v9/search" CATALOG_URL = "https://catalog.wb.ru/catalog/{shard}/v2/catalog" def __init__(self): self.client = httpx.AsyncClient( headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept": "*/*", "Origin": "https://www.wildberries.ru", "Referer": "https://www.wildberries.ru/", }, timeout=15, ) async def get_product(self, nm_id: int) -> Optional[dict]: """Получение карточки товара по артикулу WB""" params = { "appType": 1, "curr": "rub", "dest": -1257786, # Москва "nm": nm_id, } resp = await self.client.get(self.CARD_URL, params=params) resp.raise_for_status() data = resp.json() products = data.get("data", {}).get("products", []) if not products: return None return self._normalize_product(products[0]) def _normalize_product(self, raw: dict) -> dict: sizes = raw.get("sizes", []) price_data = sizes[0].get("price", {}) if sizes else {} return { "nm_id": raw["id"], "name": raw.get("name"), "brand": raw.get("brand"), "supplier_id": raw.get("supplierId"), "rating": raw.get("reviewRating"), "feedbacks": raw.get("feedbacks"), "price": price_data.get("product", 0) / 100, "sale_price": price_data.get("total", 0) / 100, "discount": raw.get("sale", 0), "colors": [c["name"] for c in raw.get("colors", [])], } async def search_products(self, query: str, page: int = 1) -> list[dict]: params = { "appType": 1, "curr": "rub", "dest": -1257786, "page": page, "query": query, "resultset": "catalog", "sort": "popular", } resp = await self.client.get(self.SEARCH_URL, params=params) resp.raise_for_status() products = resp.json().get("data", {}).get("products", []) return [self._normalize_product(p) for p in products] async def scrape_category(self, shard: str, query: str, pages: int = 5) -> list[dict]: """Обход категории постранично""" all_products = [] for page in range(1, pages + 1): products = await self.search_products(query, page) if not products: break all_products.extend(products) await asyncio.sleep(1.5) # Пауза между запросами return all_products 

Обратите внимание на asyncio.sleep(1.5) — это обязательная пауза между запросами, чтобы не словить rate limit. Для масштабного сбора мы добавляем ротацию прокси через bright data или IPRoyal.

Amazon: официальный API надёжнее

Для Amazon мы рекомендуем Product Advertising API 5.0. Он даёт доступ к ценам, рейтингам и описаниям. Парсинг через браузер здесь менее эффективен из-за агрессивной защиты. Пример:

# scraper/amazon_pa.py from paapi5_python_sdk import DefaultApi, SearchItemsRequest, PartnerType class AmazonScraper: def __init__(self, access_key: str, secret_key: str, partner_tag: str): self.api = DefaultApi( access_key=access_key, secret_key=secret_key, host="webservices.amazon.com", region="us-east-1", ) self.partner_tag = partner_tag def search_products(self, keywords: str, category: str = "All") -> list[dict]: request = SearchItemsRequest( partner_tag=self.partner_tag, partner_type=PartnerType.ASSOCIATES, keywords=keywords, search_index=category, item_count=10, resources=[ "ItemInfo.Title", "Offers.Listings.Price", "Images.Primary.Large", "ItemInfo.Features", ], ) response = self.api.search_items(request) return [self._normalize(item) for item in response.search_result.items] def _normalize(self, item) -> dict: price = None if item.offers and item.offers.listings: price = item.offers.listings[0].price.amount return { "asin": item.asin, "title": item.item_info.title.display_value if item.item_info else None, "price": price, "image": item.images.primary.large.url if item.images else None, "url": item.detail_page_url, } 

API требует партнёрского аккаунта, но данные легальны и структурированы. Для небольших объёмов это лучший вариант.

Оркестрация парсеров в Laravel

Собранные данные нужно где-то хранить и обновлять. В наших проектах мы используем Laravel с очередями и Python-скриптами, запускаемыми через Process:

// app/Console/Commands/ScrapeMarketplace.php class ScrapeMarketplace extends Command { protected $signature = 'scrape:marketplace {marketplace} {--query=} {--pages=5}'; public function handle(): void { $marketplace = $this->argument('marketplace'); $query = $this->option('query'); $pages = (int) $this->option('pages'); $process = new Process([ 'python3', base_path('scraper/run.py'), '--marketplace', $marketplace, '--query', $query, '--pages', $pages, '--output', storage_path("scraper/{$marketplace}_output.json"), ]); $process->setTimeout(300)->run(); if ($process->isSuccessful()) { $data = json_decode(file_get_contents( storage_path("scraper/{$marketplace}_output.json") ), true); foreach ($data as $item) { MarketplaceProduct::updateOrCreate( ['marketplace' => $marketplace, 'external_id' => $item['nm_id'] ?? $item['asin']], $item + ['scraped_at' => now()] ); } $this->info("Импортировано: " . count($data) . " товаров"); } else { Log::error($process->getErrorOutput()); } } } 

Такая архитектура позволяет легко масштабировать: добавили новый маркетплейс — написали отдельный скрипт и запускаем той же командой.

Антидетект-меры: чек-лист

Угроза Решение
IP-блокировка Rotating proxy (bright data, IPRoyal)
User-Agent fingerprint Randomize + обновление
Browser fingerprint Playwright stealth plugin
Rate limiting Случайные паузы 1-5 сек
CAPTCHA 2captcha / anti-captcha API
Honeypot links Фильтрация невидимых ссылок

Гарантируем, что наша конфигурация проходит 99% проверок Cloudflare.

Что входит в разработку парсера под ключ

  1. Анализ целевого маркетплейса и выбор оптимальной стратегии (API, скрейпинг, браузер)
  2. Написание парсера на Python с asyncio или Playwright
  3. Настройка ротации прокси и User-Agent
  4. Нормализация данных: приведение цен к единому формату, удаление дублей, чистка HTML
  5. Интеграция с вашей CRM, ERP или Google Sheets через REST API или CSV
  6. Документация по эксплуатации и обучение команды
  7. Поддержка в течение 3 месяцев — исправление поломок при изменении сайта

Сроки разработки

Маркетплейс Сложность Срок
Wildberries (JSON API) Средняя 3-5 дней
Ozon (Playwright) Высокая 5-8 дней
Amazon (PA API) Низкая 2-3 дня
Яндекс.Маркет Средняя 3-5 дней
+ Мониторинг и алерты +2-3 дня

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

Официальная документация Playwright