Explainers

Рабочий процесс GeeTest v3 «Вызов-ответ»: глубокое техническое погружение

CaptchaAI вернул решение GeeTest v3, а сайт его отклоняет? Причина почти всегда одна: challenge истёк раньше, чем значения дошли до формы. В отличие от reCAPTCHA, здесь нет единого токена — есть обмен несколькими значениями между сайтом, браузером и серверами GeeTest, и каждое живёт считаные минуты.

Коротко, если нужен только план действий:

  • Сайт регистрирует задание у GeeTest и получает gt + challenge.
  • Виджет в браузере рендерит слайдер/иконки по этим двум значениям.
  • После решения виджет отдаёт geetest_challenge, geetest_validate, geetest_seccode.
  • Эти три значения нужно передать в CaptchaAI и получить их обратно уже решёнными.
  • Всё окно на решение — 1–2 минуты, поэтому задержки между шагами ломают интеграцию чаще всего остального.

Протокол GeeTest v3 в двух словах

Сайт связывается с GeeTest, чтобы зарегистрировать задание:

Site Backend → GeeTest Server: "Give me a challenge for this user"
GeeTest Server → Site Backend: { gt, challenge, new_captcha }
Site Backend → Browser: Passes gt and challenge to the page

Полученные gt и challenge браузер передаёт в виджет, тот рендерит задачу, а решение пользователя проверяется сразу на двух сторонах:

Browser: Renders slider/puzzle using gt + challenge
User: Solves the challenge
Browser → Site Backend: { geetest_challenge, geetest_validate, geetest_seccode }
Site Backend → GeeTest Server: Verifies the three values
GeeTest Server → Site Backend: { result: "success" }

Для интеграции с CaptchaAI важны именно два значения из первой фазы — gt и challenge. Всё, что происходит дальше на стороне GeeTest, CaptchaAI выполняет за вас и возвращает готовый набор из трёх значений для второй фазы.

Пошагово: от регистрации до ответа сайта

Шаг 1. Регистрация на сервере GeeTest

Сайт вызывает конечную точку регистрации GeeTest:

GET https://api.geetest.com/register.php?gt=GT_ID&json_format=1

Ответ:

{
  "success": 1,
  "gt": "81dc9bdb52d04dc20036dbd8313ed055",
  "challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "new_captcha": true
}

Что означают эти поля:

  • gt — GeeTest ID, идентификатор учётной записи сайта в GeeTest;
  • challenge — уникальный токен вызова для текущей сессии;
  • new_captcha — использовать ли новый формат CAPTCHA.

challenge одноразовый и ограничен по времени: каждая загрузка страницы генерирует новый.

Шаг 2. Рендер задачи в браузере

Браузер получает gt и challenge и инициализирует виджет GeeTest:

initGeetest({
  gt: "81dc9bdb52d04dc20036dbd8313ed055",
  challenge: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  offline: false,
  new_captcha: true,
  product: "float"
}, function(captchaObj) {
  captchaObj.appendTo('#captcha-container');
  captchaObj.onSuccess(function() {
    var result = captchaObj.getValidate();
    // result contains: geetest_challenge, geetest_validate, geetest_seccode
  });
});

Шаг 3. Какие бывают типы заданий

Тип задачи выбирает GeeTest — по настройкам сайта и риск-профилю пользователя. Практически встречаются четыре варианта:

  • Слайдер — перетащить кусок пазла на место в изображении;
  • Клик по значкам — кликнуть указанные значки в показанной последовательности;
  • Клик по иероглифам — кликнуть китайские символы в правильном порядке;
  • Пространственное — задача на пространственное мышление, где нужно нажать или выбрать элемент.

Шаг 4. Значения после решения

После решения виджет отдаёт три значения:

{
  "geetest_challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy",
  "geetest_validate": "abc123def456_validate",
  "geetest_seccode": "abc123def456_validate|jordan"
}
  • geetest_challenge — изменённый токен вызова: исходный challenge плюс два дополнительных символа;
  • geetest_validate — хэш проверки;
  • geetest_seccode — код проверки, validate с добавленным суффиксом из примера (здесь — \|jordan).

Шаг 5. Проверка на сервере

Сайт отправляет эти три значения в GeeTest для проверки:

POST https://api.geetest.com/validate.php

seccode=abc123def456_validate|jordan
&challenge=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy
&sdk=geetest-python-3.0.0

GeeTest отвечает:

{
  "seccode": "abc123def456_validate",
  "validate": "abc123def456_validate"
}

Как достать gt и challenge для CaptchaAI

Чтобы решить через CaptchaAI, из страницы сайта нужны только gt и challenge — дальше протокол ведёт CaptchaAI. Рабочих способа три.

Способ 1. Перехватить ответ регистрации

from playwright.sync_api import sync_playwright
import json

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()

    geetest_params = {}

    def handle_response(response):
        if "register" in response.url and "geetest" in response.url:
            data = response.json()
            geetest_params["gt"] = data.get("gt")
            geetest_params["challenge"] = data.get("challenge")

    page.on("response", handle_response)
    page.goto("https://staging.example.com/qa-login")

    # Wait for GeeTest to load
    page.wait_for_selector(".geetest_holder")
    print(f"gt: {geetest_params.get('gt')}")
    print(f"challenge: {geetest_params.get('challenge')}")

Самый надёжный вариант — перехват сетевого ответа не зависит от того, как именно сайт отрисовал виджет на странице.

Способ 2. Извлечь из JavaScript страницы

gt = page.evaluate("() => document.querySelector('[data-gt]')?.dataset.gt")
challenge = page.evaluate("() => document.querySelector('[data-challenge]')?.dataset.challenge")

Работает, если сайт кладёт значения в data-атрибуты DOM — проверьте разметку конкретной страницы заранее.

Способ 3. Найти вызов initGeetest в исходном коде

import re
source = page.content()
gt_match = re.search(r"gt['\"]?\s*[:=]\s*['\"]([a-f0-9]{32})['\"]", source)
challenge_match = re.search(r"challenge['\"]?\s*[:=]\s*['\"]([a-f0-9]{32})['\"]", source)

Резервный вариант на случай, если первые два не сработали: значения ищутся регулярным выражением прямо в HTML/JS-источнике страницы.

Отправка в CaptchaAI и разбор ответа

Отправьте извлечённые параметры:

POST https://ocr.captchaai.com/in.php

key=YOUR_API_KEY
&method=geetest
&gt=81dc9bdb52d04dc20036dbd8313ed055
&challenge=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
&pageurl=https://staging.example.com/qa-login
&json=1

Опросите результат:

GET https://ocr.captchaai.com/res.php?key=YOUR_API_KEY&action=get&id=TASK_ID&json=1

CaptchaAI возвращает:

{
  "status": 1,
  "request": {
    "geetest_challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy",
    "geetest_validate": "abc123def456_validate",
    "geetest_seccode": "abc123def456_validate|jordan"
  }
}

Вы получаете все три значения для проверки на сайте — их нужно подставить в те же поля, куда их обычно кладёт сам виджет после решения пользователем.

Если тестовый стенд развёрнут в европейском дата-центре или у казахстанского хостера, а канал нестабильный, закладывайте запас между извлечением параметров и опросом res.php: challenge живёт всего 1–2 минуты, и лишняя сетевая задержка сжигает это окно.

Онлайн- и офлайн-режим GeeTest v3

У GeeTest v3 есть резервный режим на случай недоступности серверов GeeTest. В онлайн-режиме (success: 1) идёт обычный обмен запрос-ответ с серверами GeeTest. В офлайн-режиме (success: 0) задача формируется локально, а проверка упрощена. Подавляющее большинство сайтов работают в онлайн-режиме — офлайн стоит держать в уме как редкий edge case при отладке.

Типичные ошибки при интеграции

  • challenge пустой — регистрация не прошла: проверьте, что GeeTest вообще загрузился на странице.
  • Решение получено, но сайт его отклоняетchallenge истёк к моменту отправки: извлекайте заново и отправляйте сразу, без промежуточных задержек.
  • Неверное значение gt — на странице несколько виджетов GeeTest: берите gt именно из нужного, а не первого попавшегося в DOM.
  • Три значения получены, но форма не отправляется — не заполнены нужные поля: подставьте geetest_challenge, geetest_validate и geetest_seccode в соответствующие input.

Частые вопросы

Сколько стоит решение GeeTest v3 через CaptchaAI?

Тарифы считаются по потокам: BASIC — $15/мес, 5 потоков; STANDARD — $30/мес, 15 потоков. Актуальные цены смотрите на captchaai.com/pricing.

Сколько живёт challenge и когда его отправлять в CaptchaAI?

Обычно 1–2 минуты. Извлекайте gt и challenge и сразу передавайте их дальше, без кэширования между запусками.

CaptchaAI вернул решение, а сайт отклоняет его из-за просроченного challenge — что делать?

Между извлечением и отправкой прошло слишком много времени. Проверьте ретраи и логирование в пайплайне и уберите лишние шаги перед запросом к in.php.

Чем обмен значениями в GeeTest v3 отличается от reCAPTCHA?

В reCAPTCHA один токен закрывает весь процесс и вставляется в скрытое поле формы. GeeTest v3 требует связку из трёх значений, которые нужно подставить в разные поля после решения.

Нужен ли прокси, чтобы GeeTest v3 проходил стабильно при парсинге?

Прокси решает задачи сетевого уровня — распределение запросов, гео IP-адрес — но не заменяет корректное извлечение gt/challenge и своевременную отправку значений в CaptchaAI.

Следующие шаги

Комментарии для этой статьи отключены.