Как решить GeeTest v3 на Python и отправить результат обратно

solve geetest in python - How to Solve GeeTest v3 in Python and Post It Back

Большинство кода для капчи предполагает: один токен на входе, один на выходе. GeeTest это нарушает. Решение возвращает три значения, которые нужно отправлять вместе, а капча, которую вы передали, истекает примерно через шестьдесят секунд после того, как вы её получили. И то, и другое сбивает людей с толку, и ни одно из них не выдаёт понятного сообщения об ошибке.

Два входных значения, ведущих себя по-разному

ЗначениеПожизненно
gtСтатичен для сайта. Кэшируйте его свободно
challengeОдноразовый, недействителен примерно через 60 секунд

Оба берутся из собственного init-эндпоинта GeeTest на сайте. gt фактически является идентификатором сайта. challenge — на каждую попытку, и использование его как многоразового — самая распространённая причина, по которой интеграция GeeTest работает при тестировании и разваливается под нагрузкой.

Настройка

# Python 3.10 or newer.
pip install capskip
from capskip import CapSkip

solver = CapSkip(
    host="127.0.0.1",
    port=8080,
    recaptchaTimeout=300,   # GeeTest uses this, not defaultTimeout
)

Это различие в тайм-аутах легко упустить. defaultTimeout управляет только капчами-картинками; всё интерактивное использует recaptchaTimeout.

Распознавание

result = solver.geetest(
    gt="81388ea1fc187e0c335c0a8907ff2625",
    challenge="7cf6a8b1a2c34d5e6f7089abcdef0123",
    url="https://example.com/login",
)

print(result["challenge"])
print(result["validate"])
print(result["seccode"])

Эти три ключа — и есть ответ. result["code"] тоже заполняется, но для GeeTest оно содержит необработанную JSON-строку, а не то, что можно отправить, поэтому обращение к нему по привычке приводит к непонятному сбою.

Используйте challenge который возвращается, а не тот, что вы отправили. Это не всегда одно и то же значение.

Полный процесс в одном месте

Получение и решение должны идти вплотную. Любая задержка между ними рискует истечением срока:

import time
import requests
from capskip import CapSkip

solver = CapSkip()
LOGIN = "https://example.com/login"

# 1. Fresh pair, cache-busted. Cached init responses hand back dead challenges.
init = requests.get(
    "https://example.com/geetest/init",
    params={"t": int(time.time() * 1000)},
).json()

# 2. Solve immediately. Do not queue this.
result = solver.geetest(gt=init["gt"], challenge=init["challenge"], url=LOGIN)

# 3. Post all three together, alongside the real form fields.
response = requests.post(LOGIN, data={
    "geetest_challenge": result["challenge"],
    "geetest_validate": result["validate"],
    "geetest_seccode": result["seccode"],
    "username": "...",
    "password": "...",
})

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

Эти три имени полей — обычное соглашение GeeTest v3, но сайт может их переименовать. Проверьте реальную форму, прежде чем делать предположения.

Выполнение нескольких сразу

Ловушка здесь — неправильная пакетная обработка. Если получить кучу заданий, а затем решать их все, поздние гарантированно истекут до своей очереди. Получайте и решайте в рамках одной задачи:

import asyncio
from capskip import AsyncCapSkip

async def solve_one(solver, url):
    init = await fetch_pair(url)          # your own fetch, awaited
    return await solver.geetest(
        gt=init["gt"], challenge=init["challenge"], url=url,
    )

async def main():
    solver = AsyncCapSkip()
    return await asyncio.gather(*[solve_one(solver, u) for u in urls])

asyncio.run(main())

Python — единственный SDK CapSkip, где AsyncCapSkip — это настоящий асинхронный клиент, а не псевдоним, поэтому он действительно выполняет решения параллельно.

Когда это не срабатывает

from capskip import (
    ValidationException, NetworkException, ApiException, TimeoutException,
)

try:
    result = solver.geetest(gt=gt, challenge=challenge, url=page_url)
except ValidationException:
    pass   # missing gt or challenge
except NetworkException:
    pass   # CapSkip is not running
except ApiException:
    pass   # usually a challenge that expired before the solve finished
except TimeoutException:
    pass   # exceeded recaptchaTimeout

На практике большинство сбоев GeeTest приходят в виде ApiException и означают, что задача умерла. Решение — получать позже, а не повторять с той же парой, потому что израсходованная задача никогда снова не становится действительной.

Часто задаваемые вопросы

Почему result[“code”] нельзя использовать?

Потому что ответ — это три значения, а не одно. code сохраняет необработанный JSON для полноты, тогда как SDK разворачивает полезные части в challenge, validate и seccode. Отправьте эти три.

Можно ли кэшировать задачу между запусками?

Нет. Он одноразовый и истекает примерно через минуту. gt безопасно кэшировать; капчу — никогда.

Охватывает ли это GeeTest v4?

The geetest метод предназначен для v3 — слайдер-пазла, построенного вокруг gt и challenge пара. v4 изменил модель параметров, поэтому сверьтесь с актуальной Документация по API прежде чем предполагать, что применяется тот же вызов.

Сводка

Получить gt и challenge непосредственно перед решением с помощью запроса без кэша вызовите geetest, затем отправьте challenge, validate и seccode вместе. Используйте возвращённый challenge, а не свой ввод, и никогда не запрашивайте challenge пакетами заранее, до решения.

Другие языки — на Решение для GeeTest страница, более широкий набор возможностей Python на Решатель капчи для Python страница, и есть «живая» головоломка на нашей Демо GeeTest v3. CapSkip обрабатывает обход капчи локально, поэтому объём решений бесплатен.