Если солвер вернул токен, а сайт всё равно отклонил форму, дело чаще не в решении, а в том, что между решением и отправкой сменился исходящий IP. Отсюда правило выбора:
- одна пользовательская сессия — вход, чекаут, многошаговая форма — идёт с одного IP (sticky-режим);
- независимые запросы — каталог, выдача, мониторинг цен — распределяются по пулу (ротация).
Ошибка стоит дважды: лишние проверки CAPTCHA и лишние потоки под них.
Матрица выбора: с чего начать
| Сценарий | Режим | Причина |
|---|---|---|
| Вход, регистрация | sticky | токен сверяется с IP |
| Чекаут, оплата | sticky | cookie привязаны к IP |
| Форма с CAPTCHA | sticky | связка «токен — IP» |
| Сбор каталога | ротация | запросы независимы |
| Выдача, мониторинг цен | ротация | лимиты считаются по IP |
Как устроены оба режима
Sticky-режим закрепляет адрес на заданный TTL, ротация выдаёт новый на каждый запрос.
STICKY SESSION:
Request 1 ──▶ IP: 192.168.1.50 ──▶ site.com/login
Request 2 ──▶ IP: 192.168.1.50 ──▶ site.com/dashboard
Request 3 ──▶ IP: 192.168.1.50 ──▶ site.com/account
(Same IP for all requests in the session window)
ROTATING SESSION:
Request 1 ──▶ IP: 192.168.1.50 ──▶ site.com/page1
Request 2 ──▶ IP: 10.0.0.77 ──▶ site.com/page2
Request 3 ──▶ IP: 172.16.5.22 ──▶ site.com/page3
(Different IP per request)
Сравнение по ключевым факторам
Доли проверок ниже — ориентировочные диапазоны, они зависят от площадки.
| Фактор | sticky | ротация |
|---|---|---|
| IP на запрос | тот же 1–30 мин | новый каждый раз |
| Целостность сессии | сохраняется | отсутствует |
| Доля CAPTCHA: многошаговые сценарии | 5–10 % | 30–50 % |
| Доля CAPTCHA: отдельные страницы | 10–20 % | 5–10 % |
| Валидность токена | выше, IP не меняется | риск несоответствия |
| Скорость | выше, соединение живёт | ниже, новое соединение |
| Риск блокировки адреса | выше, если адрес помечен | ниже, адрес новый |
Где sticky-сессия обязательна
Многошаговый вход с проверкой CAPTCHA
Проверка CAPTCHA сопоставляет токен с адресом, с которого пришёл запрос. Если IP изменился между решением и отправкой, токен отклоняется, а в панели управления решение при этом числится успешным. Отсюда правило: страница, решение и отправка идут из одной requests.Session() с одним прокси.
import requests
import time
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
# Sticky session: same IP for the entire login flow
STICKY_PROXY = {
"http": "http://user-session-abc123:[email protected]:5000",
"https": "http://user-session-abc123:[email protected]:5000",
}
session = requests.Session()
session.proxies = STICKY_PROXY
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
})
def login_with_captcha(url, sitekey, username, password):
"""Full login flow — MUST use same IP throughout."""
# Step 1: Load login page (IP: 192.168.1.50)
session.get(url)
# Step 2: Solve CAPTCHA (solved against IP: 192.168.1.50)
token = solve_recaptcha(sitekey, url)
# Step 3: Submit login (MUST be IP: 192.168.1.50)
resp = session.post(url, data={
"username": username,
"password": password,
"g-recaptcha-response": token,
})
return resp.status_code == 200
def solve_recaptcha(sitekey, pageurl):
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
data = result.json()
if data["request"] != "CAPCHA_NOT_READY":
return data["request"]
raise TimeoutError("CAPTCHA solve timeout")
Почему токен теряет силу при смене IP
Sticky session:
1. Browser loads page → IP: 5.5.5.5
2. CAPTCHA solved → Token bound to session
3. Form submitted → IP: 5.5.5.5 ✅ Token accepted
Rotating session:
1. Browser loads page → IP: 5.5.5.5
2. CAPTCHA solved → Token bound to session
3. Form submitted → IP: 9.9.9.9 ❌ Token may be rejected
Так же ведёт себя Cloudflare Turnstile: токен cf-turnstile-response живёт недолго и рассчитан на ту же сессию.
Где выигрывает ротация IP
Массовый сбор страниц каталога
Состояния между запросами нет: пятьсот карточек с одного IP — всплеск частоты, те же пятьсот через пул — фон.
import concurrent.futures
ROTATING_PROXY = {
"http": "http://user:[email protected]:5000",
"https": "http://user:[email protected]:5000",
}
def scrape_page(url):
"""Each request gets a fresh IP automatically."""
resp = requests.get(
url,
proxies=ROTATING_PROXY,
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},
timeout=30,
)
if resp.status_code == 200:
return url, resp.text
return url, None
urls = [f"https://example.com/products?page={i}" for i in range(1, 501)]
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as pool:
results = list(pool.map(scrape_page, urls))
success = sum(1 for _, html in results if html)
print(f"Scraped: {success}/{len(urls)}")
Парсинг поисковой выдачи
Поисковые системы считают объём запросов по адресу: постраничный сбор выдачи — случай для ротации и пауз.
def scrape_search(query, pages=10):
results = []
for page in range(pages):
# Each request → new IP
resp = requests.get(
"https://search-engine.example.com/search",
params={"q": query, "start": page * 10},
proxies=ROTATING_PROXY,
timeout=20,
)
results.append(resp.text)
time.sleep(2)
return results
Собирайте только те данные, которые вы вправе обрабатывать: для аудитории в РФ это вопрос 152-ФЗ, для трансграничных проектов — та же логика GDPR.
Гибридная схема в одном пайплайне
На практике оба режима живут рядом: один менеджер прокси выдаёт закреплённый адрес под авторизацию, ротируемый — под остальное.
class HybridProxyManager:
"""Sticky for multi-step flows, rotating for single requests."""
def __init__(self, provider_host, username, password, port=5000):
self.host = provider_host
self.username = username
self.password = password
self.port = port
def get_rotating_proxy(self):
return {
"http": f"http://{self.username}:{self.password}@{self.host}:{self.port}",
"https": f"http://{self.username}:{self.password}@{self.host}:{self.port}",
}
def get_sticky_proxy(self, session_id, duration_min=10):
sticky_user = f"{self.username}-session-{session_id}-ttl-{duration_min}"
return {
"http": f"http://{sticky_user}:{self.password}@{self.host}:{self.port}",
"https": f"http://{sticky_user}:{self.password}@{self.host}:{self.port}",
}
proxy_mgr = HybridProxyManager("proxy.example.com", "user", "pass")
def scrape_with_auto_strategy(url, needs_login=False):
if needs_login:
# Multi-step → sticky
import uuid
session_id = uuid.uuid4().hex[:8]
proxy = proxy_mgr.get_sticky_proxy(session_id)
else:
# Single page → rotating
proxy = proxy_mgr.get_rotating_proxy()
return requests.get(url, proxies=proxy, timeout=30)
Тот же подход на Node.js
const axios = require("axios");
const CAPTCHAAI_KEY = "YOUR_API_KEY";
const PROXY_HOST = "proxy.example.com";
const PROXY_PORT = 5000;
function getProxy(mode, sessionId = null) {
const user =
mode === "sticky" ? `user-session-${sessionId}` : "user";
return {
proxy: {
host: PROXY_HOST,
port: PROXY_PORT,
auth: { username: user, password: "pass" },
},
};
}
// Rotating: bulk scrape
async function scrapePages(urls) {
const results = [];
for (const url of urls) {
const config = getProxy("rotating");
const resp = await axios.get(url, { ...config, timeout: 30000 });
results.push({ url, data: resp.data });
}
return results;
}
// Sticky: login flow
async function loginFlow(loginUrl, sitekey, credentials) {
const sessionId = Date.now().toString(36);
const config = getProxy("sticky", sessionId);
// Step 1: Load page
await axios.get(loginUrl, config);
// Step 2: Solve CAPTCHA
const submitResp = await axios.post(
"https://ocr.captchaai.com/in.php",
null,
{
params: {
key: CAPTCHAAI_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: loginUrl,
json: 1,
},
}
);
const taskId = submitResp.data.request;
let token;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const res = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: CAPTCHAAI_KEY, action: "get", id: taskId, json: 1 },
});
if (res.data.request !== "CAPCHA_NOT_READY") {
token = res.data.request;
break;
}
}
// Step 3: Submit with same IP
return axios.post(
loginUrl,
{
...credentials,
"g-recaptcha-response": token,
},
config
);
}
Какой TTL держать для sticky-сессии
| TTL | Под какие задачи | На что смотреть |
|---|---|---|
| 1 мин | отправка одной формы | истекает посреди потока |
| 5 мин | вход и пара действий | рабочий баланс |
| 10 мин | многостраничные сценарии | умеренный риск |
| 30 мин | длинные сессии просмотра | риск выше |
| 60 мин | долгие операции в кабинете | самый высокий риск |
Два ориентира при выборе значения:
- берите TTL с двукратным запасом к времени сценария;
- учитывайте сетевое плечо: у команды в Алматы, работающей через европейский регион, каждый шаг дороже по RTT, и на нестабильном канале запас важнее экономии.
Диагностика: что ломается на практике
| Симптом | Причина | Что сделать |
|---|---|---|
| токен получен, форма его отклоняет | IP сменился между шагами | перевести сценарий в sticky |
| много CAPTCHA на независимых страницах | один адрес собирает слишком много URL | перевести сбор на ротацию |
| cookie теряются посреди сценария | TTL sticky-сессии истёк | увеличить TTL |
| ротация медленнее ожидаемого | новое соединение на каждый адрес | пул соединений, keep-alive |
| адрес в sticky-сессии заблокирован | весь трафик идёт через один IP | уменьшить TTL, добавить паузы |
Как режим сессии отражается на бюджете
Провайдеру прокси вы платите одинаково в обоих режимах — разницу создаёт число проверок CAPTCHA. Тарификация CaptchaAI идёт за одновременные потоки, а не за каждое решение. BASIC ($15/мес, 5 потоков) закрывает разовые сценарии авторизации, ADVANCE ($90/мес, 50 потоков) — регулярный сбор с постоянным фоном проверок.
Отсюда два следствия:
- неверный режим не увеличивает счёт напрямую — он увеличивает поток задач и заставляет держать тариф выше ради той же скорости;
- фиксированный платёж за потоки предсказуем для команд, которые зарабатывают в местной валюте, а платят в долларах.
Частые вопросы
Как понять, что виноват режим прокси, а не сама проверка CAPTCHA?
- Логируйте исходящий адрес на каждом шаге сценария.
- Сверьте ответ
res.phpс ответом формы. - Если токен получен, а форма вернула ошибку валидации, причина в смене IP или в истёкшем токене.
Какой TTL ставить, если решение CAPTCHA занимает 20–30 секунд?
Удваивайте полное время сценария вместе с ожиданием: обычный вход — 5 минут, несколько форм подряд — 10. Ставить 60 минут «на всякий случай» не стоит.
Растёт ли расход CaptchaAI при переходе на ротацию?
Прямой связи нет: тарификация идёт по потокам, а не по числу решений. Растёт число задач, если ротацию включили там, где нужна была сессия.
Нужны ли резидентные прокси или хватит дата-центровых?
Это отдельный от режима вопрос: дата-центровые адреса дешевле и быстрее на публичных страницах, резидентные ровнее проходят там, где площадка чувствительна к происхождению трафика.
Смежные материалы
- ротация резидентных прокси при решении CAPTCHA
- почему автоматизация браузера падает, а вызов API работает
- сохранение состояния браузерной сессии
Настройки sticky-сессий у провайдеров: Bright Data, Smartproxy, Oxylabs.
Подберите режим сессии под свой сценарий — получите API-ключ CaptchaAI и подключите решение CAPTCHA к обоим режимам.