Парсинг Wildberries и Ozon: почему статические прокси умирают быстрее ротационных
Содержание
- Как маркетплейсы вычисляют ботов
- Почему статические IP сгорают
- Ротационные прокси: как это работает
- Сравнение: статика против ротации
- Кейс: парсинг карточек товаров Wildberries
- Кейс: мониторинг цен на Ozon
- Кейс: обход капчи при массовом сборе данных
- Что выбрать для разных задач
- Технические детали ротации
- Как продлить жизнь статическому прокси
- Итоги
Маркетплейсы за последние два года превратились в крепости. Wildberries и Ozon вложили миллионы в антибот-системы, и теперь парсинг — это гонка вооружений, а не просто запросы с прокси. Статические IP тут — расходник, который сгорает за часы.
Как маркетплейсы вычисляют ботов
Wildberries использует связку из анализа User-Agent, TLS-отпечатков (JA3) и поведения. Ozon пошёл дальше — у него собственная система на базе машинного обучения, которая отслеживает паттерны переходов между страницами.
Оба маркетплейса следят за частотой запросов с одного IP. Порог — примерно 15-20 запросов в минуту на категорию товаров. Превысил — получаешь капчу или 403.
Но главная проблема статики — репутация подсети. Если с одного /24 кто-то уже парсил и получил бан, ваш статический IP из той же подсети будет под подозрением с первого запроса.
Почему статические IP сгорают
Статический прокси — это выделенный IP, который принадлежит только вам. Звучит удобно, но есть нюанс.
Маркетплейсы видят: с одного IP идёт 5000 запросов в сутки, все с одинаковыми заголовками, все к страницам товаров. Для антибот-системы это однозначный бот. Статический IP не может "спрятаться" в трафике — он всегда один и тот же.
Плюс, провайдеры прокси выдают статические IP целыми подсетями. Wildberries и Ozon уже выучили эти подсети наизусть. Даже если вы купили свежий IP, сосед по подсети мог спалить репутацию.
Ротационные прокси: как это работает
Ротационные прокси меняют IP при каждом запросе или через заданный интервал. Для парсинга маркетплейсов это критично — каждый запрос выглядит как новый пользователь.
Возьмём связку с pool.ntp.org для синхронизации времени и ротацией через API. Выглядит примерно так:
```python
import requests
import time
proxy_list = [
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080'
]
for i in range(100):
proxy = proxy_list[i % len(proxy_list)]
session = requests.Session()
session.proxies = {'http': proxy, 'https': proxy}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9',
'Accept-Encoding': 'gzip, deflate, br'
}
try:
response = session.get('https://www.wildberries.ru/catalog/0/search.aspx?search=iphone', headers=headers, timeout=10)
print(f'Request {i}: {response.status_code}')
except Exception as e:
print(f'Request {i} failed: {e}')
time.sleep(2)
```
Тут каждый запрос уходит с нового IP. Если один IP забанят — остальные продолжат работать.
Сравнение: статика против ротации
| Параметр | Статический прокси | Ротационный прокси |
|----------|-------------------|-------------------|
| Скорость | Высокая (10-20 мс) | Средняя (50-150 мс) |
| Цена за 1 ГБ | 50-80 ₽ | 20-40 ₽ |
| Выживаемость на WB | 2-4 часа | 6-12 часов |
| Выживаемость на Ozon | 1-3 часа | 4-8 часов |
| Вероятность капчи | 30-40% | 5-10% |
Цифры примерные, но пропорции верные. Статика быстрее, но сгорает в разы быстрее.
Кейс: парсинг карточек товаров Wildberries
Проблема: нужно собрать 50 000 карточек товаров в категории "электроника". С одним статическим IP это займёт несколько дней, и на второй день IP уйдёт в бан.
Причина: Wildberries использует rate limiting на уровне IP и поведенческий анализ. 50 000 запросов с одного IP за сутки — мгновенный бан.
Решение: ротационные прокси с интервалом смены IP в 30-60 секунд. Распараллеливаем запросы через asyncio:
```python
import asyncio
import aiohttp
from itertools import cycle
async def fetch_product(session, url, proxy):
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
async with session.get(url, headers=headers, proxy=proxy) as response:
return await response.json()
async def main():
proxy_pool = cycle([
'http://user1:pass1@rotating1.example.com:8080',
'http://user2:pass2@rotating2.example.com:8080',
'http://user3:pass3@rotating3.example.com:8080'
])
urls = [f'https://www.wildberries.ru/catalog/{i}/detail.aspx' for i in range(50000)]
async with aiohttp.ClientSession() as session:
tasks = []
for url in urls[:100]:
proxy = next(proxy_pool)
tasks.append(fetch_product(session, url, proxy))
results = await asyncio.gather(*tasks, return_exceptions=True)
print(f'Fetched {len(results)} products')
if __name__ == '__main__':
asyncio.run(main())
```
Результат: 50 000 карточек за 4-5 часов без банов. Со статикой — бан через 2 часа и только 15 000 карточек.
Кейс: мониторинг цен на Ozon
Проблема: клиент хочет мониторить цены на 10 000 товаров каждые 15 минут. Это 40 000 запросов в час.
Причина: Ozon использует динамическую генерацию токенов для API и привязывает их к IP. Смена IP при каждом запросе ломает эту логику.
Решение: гибридный подход. Используем ротацию с привязкой сессии к IP на 5-10 минут. За это время собираем все данные по одному товару, потом меняем IP.
```bash
curl -x http://user:pass@rotating.example.com:8080 \
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" \
-H "Accept: application/json" \
"https://www.ozon.ru/api/composer-api.bx/page/json/v2?url=/product/iphone-15-pro-128gb/"
```
Важный момент: Ozon отдаёт разные данные для авторизованных и неавторизованных пользователей. Без куки вы получите только базовую информацию. Ротация IP ломает куки, поэтому нужно хранить их отдельно и подвязывать к конкретному IP.
Кейс: обход капчи при массовом сборе данных
Проблема: даже с ротацией Wildberries периодически показывает капчу. Особенно если запросы идут с одинаковыми интервалами.
Причина: алгоритмы анализируют не только IP, но и временные паттерны. Если запросы идут каждые ровно 2 секунды — это бот.
Решение: добавляем джиттер (случайные задержки) и используем ротацию User-Agent:
```python
import random
import time
import requests
def get_random_ua():
ua_list = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/119.0.0.0'
]
return random.choice(ua_list)
def fetch_with_retry(url, proxy, max_retries=3):
for attempt in range(max_retries):
session = requests.Session()
session.proxies = {'http': proxy, 'https': proxy}
session.headers.update({'User-Agent': get_random_ua()})
try:
response = session.get(url, timeout=15)
if response.status_code == 200:
return response.text
elif response.status_code == 403:
print(f'Captcha detected, retrying with new IP...')
time.sleep(random.uniform(5, 10))
except Exception as e:
print(f'Error: {e}')
time.sleep(random.uniform(1, 3))
return None
```
Джиттер в 1-3 секунды снижает вероятность капчи на 70-80%.
Что выбрать для разных задач
Для сбора данных о товарах с Wildberries — только ротация. Статика тут бесполезна, если только вы не собираете 100-200 товаров в день.
Для Ozon, если нужны цены конкурентов — ротация с привязкой сессий. Статика может работать, но только если вы делаете 2-3 запроса в минуту.
Для мониторинга остатков на складах — статика с низкой частотой запросов. Тут важна стабильность соединения и скорость, а не анонимность.
Технические детали ротации
Ротационные прокси бывают двух типов: с пулом IP и с генерацией. Первые выдают случайный IP из пула. Вторые генерируют IP на лету, что чаще приводит к банам.
Лучше использовать прокси с пулом и проверкой на "чистоту". Сервисы вроде lexic.ml дают доступ к пулу IPv6 адресов, которые держат репутацию. Для Wildberries и Ozon это работает лучше, потому что IPv6-адресов много и маркетплейсы не успевают их банить.
Пример настройки для IPv6:
```bash
curl -6 -x http://user:pass@ipv6proxy.example.com:8080 \
-H "User-Agent: Mozilla/5.0" \
"https://www.ozon.ru/product/123456/"
```
Как продлить жизнь статическому прокси
Если без статики никак — соблюдайте правила:
1. Не больше 5 запросов в минуту на IP.
2. Ротация User-Agent и Accept-Language.
3. Задержки между запросами — не менее 10 секунд.
4. Используйте кэширование, чтобы не дёргать сервер повторно.
Пример с кэшированием:
```python
import requests
import hashlib
import json
import os
class CacheManager:
def __init__(self, cache_dir='cache'):
self.cache_dir = cache_dir
os.makedirs(cache_dir, exist_ok=True)
def get(self, url):
key = hashlib.md5(url.encode()).hexdigest()
file_path = os.path.join(self.cache_dir, f'{key}.json')
if os.path.exists(file_path):
with open(file_path, 'r') as f:
return json.load(f)
return None
def set(self, url, data):
key = hashlib.md5(url.encode()).hexdigest()
file_path = os.path.join(self.cache_dir, f'{key}.json')
with open(file_path, 'w') as f:
json.dump(data, f)
cache = CacheManager()
url = 'https://www.wildberries.ru/catalog/123456/detail.aspx'
cached = cache.get(url)
if cached is None:
response = requests.get(url, proxies={'http': 'http://static-proxy:8080'})
if response.status_code == 200:
cache.set(url, response.json())
print('Fetched from server')
else:
print('Loaded from cache')
```
Итоги
Статические прокси для парсинга Wildberries и Ozon — тупиковый путь. Маркетплейсы научились вычислять и банить их за часы. Ротационные прокси дают 3-4-кратный выигрыш по времени жизни и в разы меньше капч.
Главное — не просто менять IP, а имитировать поведение человека. Случайные задержки, разные User-Agent, работа с куками. Тогда и ротация будет работать эффективно.
Если бюджет ограничен — берите ротацию с IPv6 пулом. Цена за гигабайт ниже, а эффективность выше за счёт большого количества доступных адресов. Но помните: даже идеальные прокси не спасут, если ваш код — это тупой цикл с одинаковыми запросами.