Когда ручной мониторинг убивает бюджет
Ваш магазин на 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







