Когда ручной мониторинг убивает бюджет
Ваш магазин на 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.
Что входит в разработку парсера под ключ
- Анализ целевого маркетплейса и выбор оптимальной стратегии (API, скрейпинг, браузер)
- Написание парсера на Python с asyncio или Playwright
- Настройка ротации прокси и User-Agent
- Нормализация данных: приведение цен к единому формату, удаление дублей, чистка HTML
- Интеграция с вашей CRM, ERP или Google Sheets через REST API или CSV
- Документация по эксплуатации и обучение команды
- Поддержка в течение 3 месяцев — исправление поломок при изменении сайта
Сроки разработки
| Маркетплейс | Сложность | Срок |
|---|---|---|
| Wildberries (JSON API) | Средняя | 3-5 дней |
| Ozon (Playwright) | Высокая | 5-8 дней |
| Amazon (PA API) | Низкая | 2-3 дня |
| Яндекс.Маркет | Средняя | 3-5 дней |
| + Мониторинг и алерты | +2-3 дня |
Оценим ваш проект бесплатно. Свяжитесь с нами для консультации — подберём оптимальную архитектуру и сроки. Закажите разработку парсера под ключ прямо сейчас.
Официальная документация Playwright







