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

Большинство кода для капчи предполагает: один токен на входе, один на выходе. 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 обрабатывает обход капчи локально, поэтому объём решений бесплатен.
