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

- Как прокси-пул ведёт себя при параллельном парсинге одной площадки: где начинаются баны

- Как прокси-пул ведёт себя при параллельном парсинге одной площадки: где начинаются баны

Анатомия параллельного парсинга

Прокси-пул — это не просто список IP. Это система распределения запросов, где каждый узел имеет свою историю, репутацию и лимиты. Когда вы запускаете 50 потоков через 20 прокси, вы создаёте динамическую нагрузку на каждую точку выхода. Поведение этой системы зависит от трёх факторов: скорость ротации, разнообразие подсетей и поведенческие паттерны запросов.

Площадки не банят за сам факт прокси. Они банят за аномалии. Если с одного IP за минуту приходит 200 запросов к разным товарам на маркетплейсе — это сигнал. Если с 20 IP приходит по 10 запросов с одинаковыми заголовками и интервалами — это тоже сигнал. Разница в том, что во втором случае срабатывает корреляционный анализ.

Ключевая метрика — не количество запросов в секунду, а энтропия распределения. Чем равномернее нагрузка на прокси и чем разнообразнее поведение, тем дольше живёт пул.

Как выглядит пул в коде

Типичная реализация на Python с ротацией через round-robin:

```python

import asyncio

import aiohttp

from itertools import cycle

PROXIES = [

"http://user:pass@10.0.0.1:8080",

"http://user:pass@10.0.0.2:8080",

"http://user:pass@10.0.0.3:8080",

]

async def fetch(session, url, proxy):

try:

async with session.get(url, proxy=proxy, timeout=10) as resp:

return resp.status, await resp.text()

except Exception as e:

return None, str(e)

async def worker(queue, proxy_pool):

proxy = next(proxy_pool)

async with aiohttp.ClientSession() as session:

while not queue.empty():

url = await queue.get()

status, body = await fetch(session, url, proxy)

queue.task_done()

async def main(urls, concurrency=20):

queue = asyncio.Queue()

for u in urls:

queue.put_nowait(u)

pool = cycle(PROXIES)

tasks = [asyncio.create_task(worker(queue, pool)) for _ in range(concurrency)]

await asyncio.gather(*tasks)

```

Этот код работает, но он наивен. Round-robin не учитывает состояние прокси. Если один узел уже получил 429, следующий запрос через него снова вернёт 429. Нужна обратная связь.

Где начинаются баны: триггеры на стороне площадки

Площадки используют несколько уровней защиты. Первый — rate limit по IP. Второй — rate limit по подсети /24. Третий — поведенческий анализ.

Rate limit по IP срабатывает предсказуемо. У большинства крупных сайтов порог — 60-120 запросов в минуту с одного адреса. Превышение даёт 429 с заголовком `Retry-After`. Если игнорировать этот заголовок и продолжать долбить — временный бан на 5-30 минут.

Rate limit по подсети опаснее. Если ваши 20 прокси находятся в одной /24, площадка видит 20 IP, но считает их как один сегмент. Суммарный лимит делится на всех. 20 прокси × 100 запросов = 2000 запросов с одной /24. Это уже аномалия.

Поведенческий анализ — самый коварный. Он смотрит на:

- Порядок запросов (последовательный обход каталога vs случайный)

- Заголовки (User-Agent, Accept-Language, Referer)

- Тайминги между запросами (слишком ровные — бот)

- Наличие cookies и их согласованность

Пример: сервер на nginx 1.24 с модулем limit_req и limit_conn. Конфиг:

```nginx

limit_req_zone \$binary_remote_addr zone=perip:10m rate=30r/m;

limit_req_zone \$binary_remote_addr zone=persubnet:10m rate=200r/m;

limit_conn_zone \$binary_remote_addr zone=connperip:10m;

server {

listen 80;

location /api/ {

limit_req zone=perip burst=10 nodelay;

limit_conn connperip 5;

proxy_pass http://backend;

}

}

```

Здесь 30 запросов в минуту на IP, burst 10. При 50 потоках через 20 прокси каждый IP получает 2.5 запроса в секунду — это 150 в минуту. Порог превышен в 5 раз. Баны начнутся через 20-30 секунд после старта.

Распределение по подсетям: цифры и реальность

Провайдеры прокси продают пакеты по 10, 50, 100 IP. Проблема в том, что дешёвые пулы часто имеют IP в двух-трёх /24. Проверить это просто:

```bash

curl -s "http://api.example.com/proxies" | jq -r '.[].ip' | \

awk -F. '{print \$1"."\$2"."\$3".0/24"}' | sort | uniq -c | sort -rn

```

Если вывод показывает, что 80 из 100 IP лежат в одной /24 — пул бесполезен для высоконагруженного парсинга. Площадка увидит один сегмент и забанит его целиком.

Хороший пул: минимум 5-7 разных /24, желательно из разных ASN. Провайдеры вроде Bright Data или Oxylabs дают такую ротацию, но цена кусается. Дешёвые пулы — это лотерея.

Кейс: парсинг маркетплейса с 5000 товаров

Задача: собрать цены на 5000 товаров с площадки, которая использует Cloudflare.

Первая попытка: 100 потоков, 50 прокси из одного пула за \$20. Старт в 10:00. Через 40 секунд — 60% запросов возвращают 403 с Cloudflare challenge. Через 2 минуты — все прокси в бане. Причина: все 50 IP в трёх /24, суммарная нагрузка 100 запросов в секунду. Cloudflare зафиксировал аномалию на уровне ASN.

Вторая попытка: те же 50 прокси, но 10 потоков и задержка 1-2 секунды между запросами. Скорость упала до 5 товаров в секунду. 5000 товаров — 16 минут. Банов нет, но время неприемлемо.

Третья попытка: 30 прокси из трёх разных провайдеров (10 + 10 + 10), 20 потоков, ротация с учётом ответов. Прокси, получивший 429 или 403, уходит в cooldown на 5 минут. Скорость — 15 товаров в секунду. 5000 товаров за 5.5 минут. Потери — 3% запросов, которые ушли в retry.

Разница в результате — не в количестве прокси, а в их разнообразии и адаптивной ротации.

Адаптивная ротация: код с обратной связью

Пул должен реагировать на ответы. Простая реализация с состоянием:

```python

import time

from collections import defaultdict

class ProxyPool:

def __init__(self, proxies, cooldown=300):

self.proxies = proxies

self.cooldown = cooldown

self.banned_until = defaultdict(float)

self.stats = defaultdict(lambda: {"ok": 0, "fail": 0})

def get(self):

now = time.time()

available = [p for p in self.proxies if self.banned_until[p] < now]

if not available:

return None

выбираем прокси с наименьшим числом ошибок

return min(available, key=lambda p: self.stats[p]["fail"])

def report(self, proxy, status):

if status in (429, 403, 503):

self.banned_until[proxy] = time.time() + self.cooldown

self.stats[proxy]["fail"] += 1

elif status == 200:

self.stats[proxy]["ok"] += 1

```

Этот код не идеален, но он уже спасает от каскадных банов. Прокси, получивший 429, не используется 5 минут. За это время лимит на стороне площадки сбрасывается.

Дополнительно стоит добавлять jitter к задержкам. Если все запросы идут с интервалом ровно 100 мс — это палево. Разброс 50-200 мс выглядит естественнее.

Заголовки и TLS fingerprint

Современные площадки смотрят не только на IP. TLS fingerprint (JA3) выдаёт клиента. Python requests имеет свой JA3, aiohttp — другой, curl — третий. Если все запросы идут с одинаковым JA3, а User-Agent меняется — это несостыковка.

Проверить свой JA3 можно через `curl -v https://tls.peet.ws/api/all`. Если вы используете разные User-Agent, но один JA3 — площадка может связать запросы.

Решение: использовать библиотеки с рандомизацией TLS, например `curl_cffi`:

```python

from curl_cffi import requests

resp = requests.get(

"https://example.com/api/items",

impersonate="chrome110",

proxies={"https": "http://user:pass@10.0.0.1:8080"}

)

```

`impersonate="chrome110"` подделывает TLS fingerprint под Chrome 110. Это снижает вероятность детекта на уровне handshake.

IPv6: где он помогает и где мешает

IPv6 даёт огромное адресное пространство. Провайдер может выдать /64 — это 18 квинтиллионов адресов. Площадки не могут банить по /64 так же агрессивно, как по /24 в IPv4, потому что это отрежет слишком много легитимных пользователей.

Пример: сервер с IPv6-пулом из /64. Каждый запрос идёт с нового адреса. Rate limit по IP не срабатывает, потому что каждый адрес используется один раз. Но поведенческий анализ всё ещё работает: если 1000 запросов приходят с одной /64 за минуту — это аномалия.

На практике IPv6-пулы дают прирост скорости в 2-3 раза при том же уровне банов, если правильно распределять нагрузку. Провайдер lexic.ml, например, выдаёт /64 на клиента, что позволяет ротировать адреса внутри сегмента без потери репутации.

Кейс: IPv6 vs IPv4 на одном сайте

Сайт с защитой на уровне nginx + fail2ban. IPv4-пул из 50 адресов, 30 потоков. Через 3 минуты — 12 IP в бане fail2ban (порог: 100 запросов за 10 минут с одного IP). Скорость упала на 24%.

Тот же сайт, IPv6-пул из /64, 30 потоков. Каждый запрос с нового адреса. Fail2ban не успевает банить, потому что каждый IP видит 1-2 запроса. Через 10 минут — 0 банов. Скорость стабильная.

Но есть нюанс: некоторые сайты блокируют IPv6 целиком. Если сайт не поддерживает IPv6, запросы просто не пройдут. Проверять нужно заранее:

```bash

curl -6 -I https://example.com

```

Если ответ 200 — IPv6 работает. Если timeout — сайт только на IPv4.

Кейс: когда пул не спасает

Сайт с агрессивным поведенческим анализом. 100 прокси, 50 потоков, рандомные задержки, разные User-Agent. Через 5 минут — все прокси в бане.

Причина: сайт использовал JS-челлендж, который проверял наличие `navigator.webdriver`, `window.chrome` и других свойств браузера. Прокси тут ни при чём — проблема в клиенте. Запросы шли через requests, который не выполняет JS.

Решение: headless-браузер с прокси. Но это уже другая история и другие ресурсы. Прокси-пул решает проблему IP, но не решает проблему fingerprint.

Мониторинг пула

Без мониторинга пул деградирует незаметно. Нужно отслеживать:

- Процент успешных запросов по каждому прокси

- Среднее время ответа

- Количество 429/403 за последние 5 минут

- Распределение по /24

Простой дашборд на Python с выводом в консоль:

```python

def print_stats(pool):

for proxy in pool.proxies:

s = pool.stats[proxy]

total = s["ok"] + s["fail"]

if total == 0:

continue

rate = s["ok"] / total * 100

print(f"{proxy}: {rate:.1f}% ok ({total} req)")

```

Если прокси показывает меньше 80% успеха — его нужно временно исключить. Если меньше 50% — заменить.

Итоги без итогов

Прокси-пул — это живая система. Она требует обратной связи, разнообразия и мониторинга. Баны начинаются не тогда, когда вы превысили лимит, а тогда, когда ваше поведение стало предсказуемым. Разнообразие подсетей, адаптивная ротация, реалистичные заголовки и TLS fingerprint — вот что держит пул в строю. Количество прокси — вторично.

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