Слайдер GeeTest ломает автоматизацию не из-за самого пазла, а из-за двух полей — gt и challenge: без них запрос в CaptchaAI не пройдёт проверку. Ниже — какие параметры обязательны, где их искать на странице и как вернуть готовое решение сайту, без лишней теории.
CaptchaAI решает GeeTest v3 (метод geetest) уже сейчас; поддержка GeeTest v4 пока в разработке — если сайт отдаёт version=4, эта связка параметров не подойдёт (см. изменения в GeeTest v4).
Обязательные параметры GeeTest v3
| Параметр | Обязателен | Описание |
|---|---|---|
gt |
Да | Идентификатор аккаунта GeeTest на сайте (32-значный hex). Есть в исходном коде страницы или в ответе API |
challenge |
Да | Строка, привязанная к сессии. Должна быть свежей на каждое решение |
pageurl |
Да | Полный URL страницы, где показывается CAPTCHA |
api_server |
Нет | Кастомный поддомен API-сервера GeeTest |
Перепутанный порядок этих полей или устаревший challenge — две самые частые причины, по которым решение GeeTest отклоняется сайтом ещё до того, как вы успеете разобраться, в чём дело.
Извлекаем gt и challenge со страницы
Оба значения обычно приходят двумя путями: часть встроена прямо в HTML, часть — в ответ конечной точки регистрации (register-slide). Функция ниже пробует оба варианта по очереди и возвращает то, что нашла первым:
# extract_geetest_params.py
import requests
import re
import json
def extract_geetest_v3(page_url, session=None):
"""Extract GeeTest v3 gt and challenge from a page."""
if session is None:
session = requests.Session()
session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36"
)
resp = session.get(page_url, timeout=15)
html = resp.text
# Method 1: Extract gt from HTML
gt_match = re.search(r'gt["\']?\s*[:=]\s*["\']([a-f0-9]{32})', html)
gt = gt_match.group(1) if gt_match else None
# Method 2: Find API endpoint that returns challenge
api_match = re.search(r'(https?://[^"\']+register-slide[^"\']*)', html)
challenge = None
if api_match:
api_url = api_match.group(1)
api_resp = session.get(api_url, timeout=10)
try:
data = api_resp.json()
challenge = data.get("challenge")
gt = gt or data.get("gt")
except json.JSONDecodeError:
pass
if not challenge:
# Try embedded challenge
ch_match = re.search(r'challenge["\']?\s*[:=]\s*["\']([a-f0-9]+)', html)
challenge = ch_match.group(1) if ch_match else None
return {"gt": gt, "challenge": challenge, "pageurl": page_url}
# Usage
params = extract_geetest_v3("https://staging.example.com/qa-login")
print(f"gt: {params['gt']}")
print(f"challenge: {params['challenge']}")
Если gt не находится ни одним из способов — вероятно, виджет подгружается через JavaScript уже после первой отрисовки страницы; см. раздел «Типичные ошибки» ниже. И, как обычно при парсинге чужих страниц: собирайте только те данные, которые вы вправе обрабатывать в рамках своего QA- или интеграционного сценария — это касается и 152-ФЗ для проектов с российскими пользователями, и GDPR-подхода для трансграничных.
Отправляем задачу в CaptchaAI
Дальше — стандартный цикл in.php / res.php: отправляем gt, challenge и pageurl с методом geetest, получаем id задачи и опрашиваем результат:
# solve_geetest.py
import requests
import time
import os
def solve_geetest(gt, challenge, pageurl, api_server=None):
"""Solve GeeTest v3 slide CAPTCHA via CaptchaAI."""
api_key = os.environ["CAPTCHAAI_API_KEY"]
payload = {
"key": api_key,
"method": "geetest",
"gt": gt,
"challenge": challenge,
"pageurl": pageurl,
"json": 1,
}
if api_server:
payload["api_server"] = api_server
# Submit
resp = requests.post(
"https://ocr.captchaai.com/in.php",
data=payload,
timeout=30,
)
result = resp.json()
if result.get("status") != 1:
raise RuntimeError(f"Submit failed: {result.get('request')}")
task_id = result["request"]
# Poll — GeeTest typically solves in 10-20 seconds
time.sleep(10)
for _ in range(30):
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=15)
data = resp.json()
if data.get("status") == 1:
return data["request"] # Returns challenge, validate, seccode
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(data["request"])
time.sleep(5)
raise TimeoutError("GeeTest solve timeout")
Первая пауза в 10 секунд не случайна: GeeTest v3 обычно решается быстрее чем за 12 секунд, и опрашивать res.php раньше — только лишние запросы и риск упереться в ограничение частоты. На тарифе BASIC ($15/мес, 5 потоков) этого хватает для единичных проверок в staging; для параллельного прогона десятков сценариев логичнее смотреть в сторону STANDARD ($30/мес, 15 потоков) или ADVANCE ($90/мес, 50 потоков) — по одному потоку на каждую одновременную задачу.
Передаём решение на сайт
Ответ CaptchaAI содержит три поля — challenge, validate, seccode — их нужно отправить обратно в конечную точку проверки на целевом сайте, иначе решение засчитано не будет:
# submit_solution.py
import json
def submit_geetest_solution(session, validation_url, solution, original_challenge):
"""Submit GeeTest solution to the target site."""
# Parse solution if string
if isinstance(solution, str):
solution = json.loads(solution)
payload = {
"geetest_challenge": solution.get("challenge", original_challenge),
"geetest_validate": solution.get("validate", ""),
"geetest_seccode": solution.get("seccode", ""),
}
resp = session.post(validation_url, data=payload, timeout=30)
return resp
# Complete flow
def full_geetest_flow(page_url, validation_url):
import requests
from extract_geetest_params import extract_geetest_v3
session = requests.Session()
session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36"
)
# Step 1: Extract parameters
params = extract_geetest_v3(page_url, session)
print(f"gt: {params['gt']}, challenge: {params['challenge'][:16]}...")
# Step 2: Solve
solution = solve_geetest(
params["gt"], params["challenge"], params["pageurl"],
)
print("Solved!")
# Step 3: Submit
resp = submit_geetest_solution(
session, validation_url, solution, params["challenge"],
)
print(f"Validation response: {resp.status_code}")
return resp
full_geetest_flow собирает три шага в один прогон — удобно как основа для собственного воркера или для интеграционного теста, который дергается перед каждым релизом.
Свежесть challenge: главное правило
challenge привязан к конкретной сессии и живёт недолго:
# fresh_challenge.py
import time
def get_fresh_challenge(session, register_url):
"""Always fetch a fresh challenge before solving."""
resp = session.get(register_url, timeout=10)
data = resp.json()
challenge = data.get("challenge")
if not challenge:
raise ValueError("No challenge returned")
return challenge
def solve_with_fresh_challenge(session, gt, register_url, pageurl):
"""Ensure challenge is fresh before submitting to CaptchaAI."""
challenge = get_fresh_challenge(session, register_url)
# Submit immediately — don't let it expire
solution = solve_geetest(gt, challenge, pageurl)
return solution
Главное правило: получили challenge — сразу же отправляйте его в CaptchaAI, без пауз на логирование или retry-очереди. Устаревший challenge провалится всегда, сколько бы раз вы ни повторяли запрос. Это особенно заметно на мобильных сетях или при нестабильном канале до тестового стенда: если между извлечением параметров и отправкой задачи проходит лишняя секунда на пересборку соединения, лучше сразу закладывать повторное извлечение challenge, а не повтор с тем же значением.
Нестандартный API-сервер GeeTest
Часть сайтов — особенно с инфраструктурой в Европе или Казахстане — обслуживает GeeTest через собственный поддомен вместо api.geetest.com. Такой адрес нужно передать в api_server:
# The api_server parameter specifies a custom GeeTest backend
# Default: api.geetest.com
# Custom examples: api-na.geetest.com, api.geetest.com/ajax-custom
solution = solve_geetest(
gt="abc123...",
challenge="def456...",
pageurl="https://staging.example.com/qa-login",
api_server="api-na.geetest.com", # North America endpoint
)
Если не передать api_server там, где он нужен, решение обычно отклоняется сайтом молча — без внятной ошибки от CaptchaAI, потому что сам токен корректен, просто выдан не под тот бэкенд GeeTest.
Типичные ошибки и их причины
| Проблема | Причина | Что делать |
|---|---|---|
ERROR_CAPTCHA_UNSOLVABLE |
Устаревший challenge |
Получите новый challenge прямо перед отправкой, не заранее |
validate приходит пустым |
Не та версия API | Используйте version=4 только для сайтов на GeeTest v4 |
| Сайт отклоняет решение | Не отправлен seccode |
Проверьте, что уходят все три поля — challenge, validate, seccode |
gt не находится на странице |
Виджет подгружается через JavaScript | Разбирайте XHR-ответы конечной точки регистрации или используйте Selenium |
Вопросы, которые часто задают про параметры GeeTest
Чем gt отличается от challenge?
gt — это идентификатор аккаунта GeeTest на сайте, он не меняется от запроса к запросу. challenge генерируется под каждую сессию заново и извлекается непосредственно перед решением.
Сколько живёт challenge и когда его лучше извлекать?
Обычно 60–120 секунд. Извлекайте его прямо перед вызовом CaptchaAI, а не заранее по расписанию — старое значение приведёт к ERROR_CAPTCHA_UNSOLVABLE независимо от того, насколько корректны остальные параметры.
gt не находится ни в HTML, ни в ответе API — что делать?
Значит, виджет GeeTest рендерится динамически через JavaScript уже после загрузки страницы. Откройте вкладку сети в браузере, найдите запрос к register-slide, и заберите gt/challenge из его ответа — либо используйте headless-браузер, который дожидается полной отрисовки перед парсингом.
Сколько потоков нужно для стабильного прогона GeeTest?
Один поток закрывает одну задачу от отправки до получения решения. Для редких ручных проверок хватает BASIC (5 потоков); для параллельных сценариев в CI — считайте по числу одновременных сессий и берите тариф с запасом, а не впритык.
Решение отклонено сайтом, хотя challenge был свежим — в чём дело?
Скорее всего, до конечной точки проверки дошли не все три поля. Проверьте, что вы отправляете challenge, validate и seccode одновременно, а не только одно-два из них — если validate пустой, взгляните на раздел «Типичные ошибки» выше: чаще всего причина в несовпадении версии GeeTest на сайте и в запросе.
Похожие материалы
Разобрались с параметрами GeeTest v3 — переходите к CaptchaAI и отправляйте первое решение через API.