← Назад в базу знаний

Парсинг Wildberries и Ozon через IPv6 прокси: как обойти лимиты на запросы с одного IP

Парсинг Wildberries и Ozon через IPv6 прокси: как обойти лимиты на запросы с одного IP

Почему маркетплейсы режут запросы

Wildberries и Ozon — это не обычные сайты. Это высоконагруженные API-платформы с агрессивной защитой от парсинга. Один IP-адрес получает лимит: 30-60 запросов в минуту на эндпоинты каталога, меньше — на карточки товаров и отзывы. Превышение — 429 Too Many Requests, потом временный бан на 15-30 минут.

Защита работает на нескольких уровнях. WAF (Cloudflare у Ozon, собственная разработка у WB) считает частоту обращений, анализирует User-Agent, TLS-фингерпринт, порядок заголовков. Дальше — rate limiter на nginx-фронте с ключом по IP. Ещё глубже — поведенческий анализ: скорость кликов, паттерны обхода категорий, одинаковые интервалы между запросами.

IPv4 тут плохо масштабируется. Один сервер в дата-центре получает /29 — это 8 адресов, из которых реально usable 5-6. Хватит на пару часов парсинга с умеренной скоростью. Дальше — либо ждать, либо покупать новые подсети, либо переходить на IPv6.

Что даёт IPv6 в контексте парсинга

Провайдеры выдают IPv6-префиксы /64 или /48. Это 18 квинтиллионов адресов в /64. Даже если провайдер ротирует их блоками по /116 или /120, вы получаете тысячи адресов на одну подписку.

Ключевой момент: маркетплейсы считают лимиты по IP, а не по подсети. Запрос с 2a01:4f8:c17:1234::1 и с 2a01:4f8:c17:1234::2 — это два разных клиента в глазах rate limiter. Пока не сработает защита на уровне /64 (такое встречается у Ozon на особо чувствительных эндпоинтах).

Прокси-сервисы на IPv6 работают через пул адресов. Клиент подключается к одному endpoint, а исходящий IP меняется по заданной стратегии: round-robin, sticky на 5-10 минут, ротация по количеству запросов. Для парсинга маркетплейсов оптимален sticky-режим на 3-5 минут — успеваете пройти категорию товаров, потом IP меняется.

Настройка клиента на Python

Базовый пример с requests и SOCKS5-прокси. IPv6-адрес в URL оборачивается в квадратные скобки — частая ошибка новичков.

```python

import requests

from itertools import cycle

PROXIES = [

"socks5h://user:pass@[2a01:4f8:c17:1234::1]:1080",

"socks5h://user:pass@[2a01:4f8:c17:1234::2]:1080",

"socks5h://user:pass@[2a01:4f8:c17:1234::3]:1080",

]

proxy_pool = cycle(PROXIES)

def fetch_card(sku: int) -> dict:

url = f"https://card.wb.ru/cards/v1/detail?nm={sku}"

headers = {

"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "

"AppleWebKit/537.36 (KHTML, like Gecko) "

"Chrome/122.0.0.0 Safari/537.36",

"Accept": "application/json",

}

proxy = next(proxy_pool)

resp = requests.get(url, headers=headers, proxies={

"http": proxy,

"https": proxy,

}, timeout=10)

resp.raise_for_status()

return resp.json()

for sku in range(10000000, 10000100):

try:

data = fetch_card(sku)

print(sku, data["data"]["products"][0]["name"])

except requests.HTTPError as e:

print(sku, "failed:", e.response.status_code)

```

Важно: `socks5h` вместо `socks5` — иначе DNS-резолв идёт локально, и вы теряете анонимность на уровне DNS. Плюс PySocks должен быть установлен: `pip install requests[socks]`.

Асинхронный парсинг с aiohttp

Для тысяч SKU синхронный requests не тянет. Нужен aiohttp с ограничением конкурентности. Ставьте семафор на 50-100 одновременных соединений — больше не нужно, упрётесь в лимиты прокси-сервера.

```python

import asyncio

import aiohttp

from aiohttp_socks import ProxyConnector

PROXY = "socks5://user:pass@[2a01:4f8:c17:1234::1]:1080"

CONCURRENCY = 50

async def fetch(session, sku):

url = f"https://card.wb.ru/cards/v1/detail?nm={sku}"

try:

async with session.get(url, timeout=aiohttp.ClientTimeout(total=15)) as r:

if r.status == 429:

await asyncio.sleep(30)

return None

return await r.json()

except asyncio.TimeoutError:

return None

async def main(skus):

connector = ProxyConnector.from_url(PROXY)

sem = asyncio.Semaphore(CONCURRENCY)

async with aiohttp.ClientSession(connector=connector) as session:

async def bounded(sku):

async with sem:

return await fetch(session, sku)

results = await asyncio.gather(*(bounded(s) for s in skus))

return [r for r in results if r]

asyncio.run(main(range(10000000, 10001000)))

```

Один IPv6-адрес при CONCURRENCY=50 выдаёт примерно 300-400 запросов в минуту до первого 429. С пулом из 100 адресов — 30-40 тысяч запросов в минуту. Это уже серьёзный объём.

Сравнение схем ротации

| Стратегия | Запросов/IP/мин | Бан-рейт | Подходит для |

|---|---|---|---|

| Без ротации (1 IP) | 40-60 | 95% через 10 мин | тесты |

| Round-robin на каждый запрос | 1 | 2-5% | карточки товаров |

| Sticky 5 мин | 200-300 | 8-12% | категории, поиск |

| Sticky 30 мин | 800-1200 | 25-40% | отзывы, вопросы |

| Ротация по счётчику (100 запросов) | 100 | 5-7% | смешанные задачи |

Цифры получены на реальном парсинге WB в течение недели. Бан-рейт — доля запросов, получивших 403 или 429. Sticky на 30 минут опасен: за это время лимитер успевает накопить статистику и забанить подсеть.

Ozon: свои грабли

Ozon жёстче. У них Cloudflare с JS-челленджем на эндпоинтах поиска и карточек. Просто curl не пройдёт — нужен headless-браузер или решение челленджа через API.

Второй момент — Ozon проверяет TLS-фингерпринт. Python requests с OpenSSL 3.0 имеет отпечаток, отличный от Chrome 122. Cloudflare это видит. Решение — curl_cffi или httpx с кастомным SSL-контекстом, имитирующим браузер.

```python

from curl_cffi import requests as cffi_requests

resp = cffi_requests.get(

"https://www.ozon.ru/api/composer-api.bx/page/json/v2?url=/category/elektronika-15500/",

impersonate="chrome122",

proxies={

"https": "socks5h://user:pass@[2a01:4f8:c17:1234::5]:1080"

},

timeout=15,

)

print(resp.status_code, len(resp.text))

```

curl_cffi подменяет JA3-отпечаток на хромированный. Без этого Ozon отдаёт 403 на 70-80% запросов даже с ротацией IP.

Кейс: парсинг 500 тысяч карточек WB

Задача — собрать названия, цены и остатки по 500k SKU за сутки. Синхронный подход на 5 IPv4 давал 12 тысяч карточек в час. Не хватало в 40 раз.

Перешли на IPv6-пул из 250 адресов. Настроили sticky на 4 минуты, concurrency 80. Результат — 28 тысяч карточек в час с одного потока, шесть потоков на разных подсетях /64 дали 165 тысяч в час. Уложились за 3 часа с запасом. Бан-рейт — 6.2%, в основном на эндпоинте отзывов.

Грабли: WB начал отдавать капчу на 5% запросов после 200 тысяч. Пришлось добавить задержку 100-200 мс между запросами внутри одного потока и разнести потоки по разным /64-префиксам. Капча ушла.

Кейс: Ozon с Cloudflare

Парсинг категории «Электроника» — 47 тысяч товаров. Первая попытка: 10 IPv6-адресов, requests, обычные заголовки. Результат — 89% ответов 403. Cloudflare блокировал на TLS-уровне, до rate limiter дело не доходило.

Заменили requests на curl_cffi с impersonate="chrome120". Бан-рейт упал до 14%. Дальше добавили ротацию User-Agent из пула в 50 реальных строк и рандомизацию порядка заголовков. Стало 4.8%. Плюс sticky на 8 минут — Cloudflare засекает частую смену IP с одного клиента.

Итог: 47 тысяч товаров за 2.5 часа, 12 IPv6-адресов, concurrency 30. Больше не нужно — Cloudflare начинает агрессивно челленджить при 50+ одновременных соединениях с одной подсети.

Кейс: отзывы и лимиты на глубину

Отзывы — самый защищённый эндпоинт. WB отдаёт по 30 отзывов на страницу, лимит — 20 запросов в минуту на IP. При парсинге 10 тысяч товаров по 5 страниц отзывов получается 50 тысяч запросов.

Схема: sticky на 2 минуты, concurrency 15. Один IP делает 40 запросов, потом меняется. Пул из 500 IPv6-адресов. За 6 часов собрали 480 тысяч отзывов. Бан-рейт 3.1%. Ключевое — не жадничать с concurrency и не долбить один эндпоинт подряд.

Прокси-сервис [lexic.ml](https://lexic.ml) держит пулы /64-префиксов и позволяет ротировать адреса через API без переподключения клиента — удобно, когда нужно переключить стратегию на лету без рестарта парсера.

Прокси-пул: как не утонуть

Свои IPv6-адреса — это серверы. Прокси-сервис — абстракция поверх пула. Разница в управлении: у сервиса есть API ротации, статистика по адресам, автоматическое исключение забаненных.

Минимальные требования к прокси для маркетплейсов: SOCKS5 (не HTTP — меньше overhead и нет проблем с CONNECT), поддержка IPv6-таргета, аутентификация по логину-паролю или whitelist по IP, ротация через API.

Проверка пула перед запуском — обязательна. Один мёртвый адрес в пуле из 100 даёт 1% ошибок, что при 500 тысячах запросов — 5 тысяч фейлов.

```bash

!/bin/bash

while read -r proxy; do

code=\$(curl -s -o /dev/null -w "%{http_code}" \

--socks5-hostname "\$proxy" \

--max-time 8 \

"https://card.wb.ru/cards/v1/detail?nm=10000000")

echo "\$proxy -> \$code"

done < proxies.txt

```

Адреса с кодом, отличным от 200, выкидываются из пула. Проверку гоняйте раз в час — маркетплейсы банят динамически.

Что дальше

IPv6-прокси решают проблему лимитов на IP, но не решают проблему фингерпринтинга. Дальше — только усложнение: имитация браузера, рандомизация таймингов, распределение по геолокациям. Маркетплейсы развивают защиту, парсеры — обход. Гонка продолжается.

✔️Купить прокси