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

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

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

Почему маркетплейсы вообще упираются в IP

Wildberries и Ozon — это не просто сайты с товарами. Это API-платформы с жёстким rate limiting, региональной привязкой цен и антифродом, который смотрит на IP-адрес клиента. Один и тот же товар в Москве и Новосибирске может стоить по-разному, а иногда и вовсе отсутствовать в выдаче для конкретного региона.

Когда вы парсите каталог с одного IP, вы упираетесь в три стены одновременно. Первая — лимит запросов с адреса. Вторая — геолокация, по которой маркетплейс подставляет цены и склад. Третья — бан за аномальное поведение, если с одного IP идёт 50 тысяч запросов в час.

IPv6 здесь даёт то, чего не может IPv4: у вас не один адрес, а пул из миллиардов. Провайдер выдаёт /64 или /48 — это 18 квинтиллионов адресов в одном префиксе. Каждый запрос можно делать с нового адреса, и для маркетплейса это выглядит как трафик из разных сетей.

Что именно ограничивают WB и Ozon

У Wildberries публичный API на `suppliers-api.wildberries.ru` и `card.wb.ru`. Rate limit по документации — около 300 запросов в минуту на один ключ, но по факту при парсинге каталога через `card.wb.ru` вы упираетесь в лимит по IP задолго до этого. Ответ приходит с кодом 429 и заголовком `X-Ratelimit-Retry: 60`.

Ozon жёстче. Их `api-seller.ozon.ru` требует OAuth-токен, а публичный поиск на `ozon.ru/api/composer-api.bx` отдаёт 403 после 200-300 запросов с одного адреса за короткое время. Плюс есть отдельный слой защиты — они смотрят на TLS-фингерпринт и заголовки.

Региональная привязка работает через заголовок `X-Forwarded-For` и геобазу по IP. Если вы делаете запрос с московского адреса, WB вернёт цены для Москвы и склады Коледино, Электросталь. С новосибирского — цены с учётом локальной логистики, которые выше на 5-15% для ряда категорий.

Как IPv6 обходит лимиты

Ключевая идея: маркетплейс видит не «один клиент с 50 тысячами запросов», а «50 тысяч клиентов с одним запросом каждый». Если у вас /64 префикс, вы можете генерировать адреса программно и ротировать их между запросами.

```bash

Проверяем, что у вас есть IPv6 префикс

ip -6 addr show dev eth0 | grep inet6

Пример: /64 префикс 2a01:4f8:1c1c:abcd::/64

Генерируем случайный адрес из префикса

python3 -c "

import random

prefix = '2a01:4f8:1c1c:abcd'

suffix = ':'.join(f'{random.randint(0, 0xffff):x}' for _ in range(4))

print(f'{prefix}:{suffix}')

"

```

Ротация на уровне сокета в Python выглядит так:

```python

import socket

import random

import requests

from requests.adapters import HTTPAdapter

from urllib3.util.connection import create_connection

PREFIX = "2a01:4f8:1c1c:abcd"

def random_ipv6():

suffix = ":".join(f"{random.randint(0, 0xffff):x}" for _ in range(4))

return f"{PREFIX}:{suffix}"

_original_create_connection = create_connection

def patched_create_connection(address, *args, **kwargs):

host, port = address

source = (random_ipv6(), 0)

return _original_create_connection(address, *args, source_address=source, **kwargs)

urllib3.util.connection.create_connection = patched_create_connection

session = requests.Session()

session.mount("https://", HTTPAdapter(max_retries=3))

for page in range(1, 100):

r = session.get(

"https://card.wb.ru/cards/detail",

params={"nm": 12345678, "dest": -1257786},

timeout=10,

)

print(page, r.status_code, len(r.content))

```

Здесь `source_address` заставляет ядро Linux использовать конкретный исходящий IPv6. Провайдер должен маршрутизировать весь /64 на ваш сервер — обычно это делается через `ip -6 route add local 2a01:4f8:1c1c:abcd::/64 dev lo`.

Реальный кейс: парсинг цен WB по регионам

Сервер на Hetzner CX22, Ubuntu 22.04, префикс /64. Задача — собрать цены по 47 регионам для 12 тысяч SKU. Наивный подход с одного IPv4 дал 429 на 340-м запросе и бан через 20 минут.

Причина — WB считает запросы по IP с окном в 60 секунд. При 300 запросах в минуту с одного адреса включается мягкий лимит, при 500 — жёсткий бан на час.

Решение: ротация IPv6 каждые 10 запросов. Скрипт поднимал 8 параллельных воркеров, каждый со своим пулом адресов. Пропускная способность выросла до 2400 запросов в минуту без единого 429. Полный обход 12 тысяч SKU по 47 регионам занял 4 часа 20 минут против расчётных 30+ часов на IPv4 с прокси-пулом.

Технические детали: `dest` параметр в API WB отвечает за регион. Для Москвы `dest=-1257786`, для Новосибирска `dest=-1235806`. Без правильного `dest` вы получите цены по умолчанию, а не по региону.

Ozon и его трюки с TLS

Ozon смотрит не только на IP, но и на JA3-фингерпринт TLS-хендшейка. Если вы используете `requests` с дефолтным OpenSSL, фингерпринт совпадает у миллионов клиентов. Это палево.

Для обхода нужен либо `curl_cffi` с эмуляцией Chrome, либо ротация TLS-стека. Пример с `curl_cffi`:

```python

from curl_cffi import requests as cffi_requests

import random

PREFIX = "2a01:4f8:1c1c:abcd"

def random_ipv6():

return f"{PREFIX}:" + ":".join(f"{random.randint(0,0xffff):x}" for _ in range(4))

session = cffi_requests.Session(impersonate="chrome124")

for query in ["iphone 15", "samsung s24", "xiaomi 14"]:

r = session.get(

"https://www.ozon.ru/api/composer-api.bx/page/json/v2",

params={"url": f"/search/?text={query}"},

headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},

timeout=15,

)

print(query, r.status_code, len(r.text))

```

`impersonate="chrome124"` подменяет весь TLS-стек на тот, что использует Chrome 124. JA3 совпадает с реальным браузером, Ozon не видит разницы на уровне хендшейка.

Привязка source address в `curl_cffi` делается через `interface` параметр, но проще ротировать на уровне сети через `ip6tables` SNAT или использовать прокси-сервер на том же хосте.

Сравнение подходов

| Метод | Запросов/мин | Стоимость | Бан-риск |

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

| IPv4 + residential прокси | 200-400 | \$3-8 за GB | Низкий |

| IPv4 datacenter пул | 100-200 | \$0.5-1 за IP | Высокий |

| IPv6 /64 ротация | 2000+ | \$5/мес за VPS | Низкий |

| IPv6 /48 ротация | 10000+ | \$15-30/мес | Очень низкий |

Цифры для WB при 10-секундном таймауте и 8 воркерах. Ozon даёт примерно в 2 раза меньше из-за более агрессивного антифрода.

Проблемы, на которые наступают все

Первая — провайдер не маршрутизирует /64. Многие хостеры выдают только /128 или /112. Проверяйте до покупки: `ip -6 route` должен показывать ваш префикс как `local` или через `dev lo`.

Вторая — IPv6-адреса из одного /64 могут быть в одной геобазе. Если вы парсите регионы, /64 из Германии даст вам немецкие цены, а не московские. Нужны префиксы из разных ASN или хотя бы разных географических зон.

Третья — DNS. Если резолвер возвращает IPv4-адрес маркетплейса, ваш IPv6 source address не применится. Форсируйте IPv6 через `socket.AF_INET6` или используйте `curl --ipv6`.

Четвёртая — MTU. IPv6 не фрагментирует пакеты на роутерах, минимальный MTU 1280 байт. Если у вас PPPoE с MTU 1492, часть пакетов будет теряться. Проверяйте `ping6 -M do -s 1452`.

Кейс: Ozon и лимит по сессии

Клиент парсил Ozon для сравнения цен. Схема: 50 IPv6-адресов, ротация каждые 5 запросов. Первые 2 часа — 1800 запросов в минуту, всё чисто. На третьем часу — массовые 403.

Причина оказалась не в IP. Ozon ставит cookie `__ozon` с идентификатором сессии и привязывает его к фингерпринту браузера. Даже с новым IP, но тем же cookie — бан.

Решение: полный сброс cookies и localStorage между запросами. В `curl_cffi` это `session.cookies.clear()` плюс новый `Session()` каждые 20 запросов. Пропускная способность упала до 900 запросов в минуту, зато без банов.

Технические детали: Ozon отдаёт `Set-Cookie` с флагами `Secure; HttpOnly; SameSite=Lax`. Cookie живёт 30 дней. Привязка идёт по хешу от `(cookie_id + ja3 + ip_prefix / 48)`. Если меняете только последние 80 бит адреса — Ozon видит тот же /48 и склеивает сессии.

Кейс: WB и региональные цены

Задача — отслеживать динамику цен на 500 SKU в 12 регионах каждые 15 минут. Итого 6000 запросов за цикл.

На старте использовали один /64 из Нидерландов. WB возвращал цены для Амстердама — то есть базовые, без региональной наценки. Клиент не понимал, почему данные не сходятся с реальным сайтом.

Причина: WB определяет регион по IP через геобазу MaxMind. Нидерландский префикс = европейский регион, цены в евро по внутреннему курсу.

Решение: арендовали /48 у российского хостера, разбили на 12 подсетей /52 по регионам. Для каждого региона — свой пул адресов, геобаза показывает нужный город. Плюс параметр `dest` в API, который явно указывает регион. Данные сошлись с реальным сайтом с точностью до копейки.

Кейс: бан по ASN

Парсинг Ozon с пула IPv6 от крупного европейского хостела. Через сутки — блокировка всего /48. Причём не по IP, а по ASN.

Причина: Ozon ведёт чёрный список автономных систем, с которых идёт подозрительная активность. Один клиент хостела нагадил — страдают все.

Решение: разнести трафик по нескольким мелким хостелам с разными ASN. Дешевле, чем residential прокси, но требует больше настройки. Плюс ротация ASN раз в неделю.

Технические детали: проверяйте ASN через `whois -h whois.radb.net` или `bgp.he.net`. Если ваш /48 принадлежит Hetzner (AS24940) или OVH (AS16276) — готовьтесь к повышенному вниманию. Мелкие хостеры с ASN в диапазоне 200000+ живут дольше.

Практика: прокси-сервер на IPv6

Простейшая схема — поднять на VPS с /64 SOCKS5-прокси, который сам ротирует исходящий IPv6. `3proxy` умеет это из коробки:

```

3proxy.cfg

nserver 1.1.1.1

nserver 2606:4700:4700::1111

nscache 65536

timeouts 1 5 30 60 180 1800 15 60

Внешние IPv6 из префикса

external 2a01:4f8:1c1c:abcd::1

external 2a01:4f8:1c1c:abcd::2

external 2a01:4f8:1c1c:abcd::3

SOCKS5 на localhost

socks -p1080 -i127.0.0.1 -e2a01:4f8:1c1c:abcd::1

```

Дальше в Python указываете `socks5://127.0.0.1:1080` и ротируете `external` через API 3proxy или перезапуск с новым конфигом. Проще — использовать `ip6tables` с random SNAT:

```bash

ip6tables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 2a01:4f8:1c1c:abcd::1-2a01:4f8:1c1c:abcd::ffff

```

Это даёт ротацию на уровне ядра, без перезапуска прокси. Каждое новое соединение получает случайный source address из диапазона.

Что делать с капчей

WB и Ozon иногда кидают капчу при подозрительной активности. С IPv6-ротацией это реже, но случается. Решение — снижать частоту запросов с подозрительных адресов или использовать сервисы разгадывания.

Но честно: если вы дошли до капчи, значит схема работает плохо. Правильная ротация IPv6 + реалистичный JA3 + сброс cookies дают 99%+ успешных запросов без капчи. Если капча появляется — пересматривайте пул адресов, скорее всего ваш /48 в чёрном списке.

Итоги по инфраструктуре

Для парсинга WB хватает /64 от нормального хостера и ротации каждые 10 запросов. Для Ozon нужен /48, ротация каждые 5 запросов, сброс cookies каждые 20, эмуляция Chrome TLS. Для обоих — минимум 3 разных ASN, чтобы не потерять всё сразу.

Бюджет: VPS с /48 в РФ — 300-500 рублей в месяц. Три таких — 1500 рублей. Против \$200-500 за residential прокси-пул. Разница очевидна.

Проверяйте маршрутизацию префикса до покупки. Тестируйте MTU. Логируйте коды ответов и заголовки `X-Ratelimit-*`. И не забывайте, что маркетплейсы обновляют защиту — то, что работало месяц назад, сегодня может дать 403 на первом же запросе.

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