API Tutorials

Paramètres du CAPTCHA GeeTest slide et guide de l'API

Une résolution GeeTest v3 tient à deux paramètres : gt, qui identifie le compte GeeTest du site et ne change jamais, et challenge, régénéré à chaque session et valable quelques secondes seulement. Vous les extrayez de la page, vous les transmettez à CaptchaAI, puis vous renvoyez les trois valeurs signées au site cible : c'est tout le mécanisme. Ce guide détaille chaque champ de la méthode geetest, montre comment récupérer les paramètres depuis une page réelle et comment éviter l'erreur la plus fréquente — le challenge périmé.


Les quatre paramètres à connaître

La soumission GeeTest v3 repose sur quatre champs. Deux sont obligatoires et identifient la session, un pointe vers la page, le dernier ne sert que sur les intégrations personnalisées.

Paramètre Obligatoire Rôle
gt Oui ID de compte GeeTest (32 caractères hexadécimaux). Présent dans la source de la page ou dans la réponse de l'API
challenge Oui Chaîne de défi propre à la session. Doit être neuve à chaque résolution
pageurl Oui URL complète de la page qui affiche le CAPTCHA
api_server Non Sous-domaine du serveur API GeeTest, uniquement si le site en utilise un personnalisé

Retenez la distinction : gt est stable et se réutilise, challenge est volatile et se jette après un seul usage. Cette asymétrie explique la quasi-totalité des échecs.


Extraire gt et challenge d'une page

Deux stratégies couvrent la plupart des sites. La première lit directement le gt dans le HTML au format hexadécimal ; la seconde suit l'endpoint register-slide qui renvoie le challenge frais côté serveur. Le code ci-dessous tente les deux et retombe sur un challenge embarqué dans la page si l'appel réseau échoue.

# 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://example.com/login")
print(f"gt: {params['gt']}")
print(f"challenge: {params['challenge']}")

Si gt ressort à None, les paramètres sont probablement injectés en JavaScript après le chargement : pilotez alors la page avec Selenium ou lisez les réponses XHR pour retrouver l'appel register-slide.


Envoyer le GeeTest à CaptchaAI

L'envoi se fait sur in.php avec method=geetest, puis vous interrogez res.php jusqu'à obtenir la réponse. GeeTest v3 se résout en général en moins de 12 secondes ; le code attend 10 secondes avant la première interrogation, puis répète toutes les 5 secondes. Ces durées reposent sur des mesures observées et varient selon l'environnement, le volume et le moment de la journée.

# 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")

La réponse contient trois valeurs : challenge, validate et seccode. Ce sont elles, et non un simple token, que le site attend pour valider le glissement.


Renvoyer la solution au site cible

CaptchaAI vous rend les valeurs signées, mais c'est votre code qui doit les rejouer sur l'endpoint de validation du site, dans les champs geetest_challenge, geetest_validate et geetest_seccode. Réutilisez la même session HTTP que pour l'extraction : le cookie de session lie le glissement au challenge d'origine.

# 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

Le flux complet enchaîne les trois étapes dans l'ordre : extraire, résoudre, renvoyer. Réutiliser un ancien challenge au lieu d'en extraire un frais est la cause n° 1 des rejets.


Le challenge expire vite : gardez-le frais

Le challenge est propre à la session et n'a qu'une courte fenêtre de validité. Récupérez-le juste avant l'envoi à CaptchaAI, jamais à l'avance et jamais en réserve.

# 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

Règle à retenir : extrayez le challenge et soumettez-le à CaptchaAI dans la foulée, en quelques secondes. Un challenge obsolète échoue systématiquement, quel que soit le reste de votre code.


Cibler un serveur GeeTest personnalisé

Certains sites ne pointent pas vers api.geetest.com mais vers un sous-domaine régional ou dédié. Dans ce cas, passez le paramètre api_server pour que CaptchaAI interroge le bon backend.

# 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://example.com/login",
    api_server="api-na.geetest.com",  # North America endpoint
)

Pour la trouver, inspectez les requêtes réseau de la page et cherchez un domaine api-*.geetest.com.


Exemple : une collecte de données conforme au RGPD

Prenons une équipe data basée à Lyon qui agrège, depuis son propre espace client, les tarifs publics d'un fournisseur dont le portail affiche un GeeTest v3 à la connexion. Le périmètre est net : des données que l'entreprise a le droit de consulter, sur un compte qui lui appartient. Le réflexe RGPD s'applique — minimisez les données personnelles collectées et ne journalisez que le nécessaire.

Techniquement, chaque connexion déclenche un nouveau challenge : le script l'extrait avec gt, les envoie à CaptchaAI via la méthode geetest, récupère validate et seccode, puis rejoue la connexion. Pour un volume modéré — quelques centaines de connexions par jour — le plan BASIC ($15/mois, 5 threads) suffit largement : chaque thread traite un CAPTCHA à la fois, avec un nombre de résolutions illimité et aucune facturation à l'unité. Pour paralléliser sur plusieurs comptes autorisés, un palier comme ADVANCE ($90/mois, 50 threads) absorbe la charge. Déployez enfin vos workers près de la cible — une région comme eu-west-3 (Paris) chez OVHcloud ou Scaleway — pour réduire la latence.


Dépannage

Problème Cause probable Correctif
ERROR_CAPTCHA_UNSOLVABLE Le challenge avait expiré avant la résolution Récupérez un challenge neuf juste avant l'envoi, puis soumettez immédiatement
Le champ validate revient vide gt ou challenge incorrect, ou challenge déjà consommé Vérifiez que gt fait 32 caractères hexadécimaux et que le challenge vient de la même session
La solution est rejetée par le site seccode absent du renvoi Transmettez bien les trois champs geetest_challenge, geetest_validate et geetest_seccode
gt introuvable dans le HTML Paramètres injectés en JavaScript Inspectez les réponses XHR (endpoint register-slide) ou pilotez la page avec Selenium

À noter : GeeTest v4 change de format (il abandonne le couple gt/challenge) et n'est pas encore pris en charge par CaptchaAI — sa prise en charge est annoncée comme à venir. Ce guide et le code ci-dessus concernent uniquement GeeTest v3.


FAQ

CaptchaAI prend-il en charge GeeTest v4 ?

Non — pas encore. Seul GeeTest v3 est pris en charge aujourd'hui ; GeeTest v4 est annoncé comme à venir et ne doit pas être considéré comme disponible. Utilisez la méthode geetest uniquement pour les sites en v3.

Faut-il un navigateur comme Selenium pour extraire les paramètres ?

Pas toujours. Si gt et l'endpoint register-slide sont présents dans le HTML ou accessibles via une requête directe, une simple session requests suffit. Selenium ne devient nécessaire que lorsque les paramètres sont injectés en JavaScript après le rendu.

Pourquoi ma solution est-elle refusée alors que la résolution a réussi ?

Le plus souvent, le challenge renvoyé au site ne correspond plus à la session, ou le seccode manque. Rejouez les trois valeurs dans la même session HTTP que l'extraction, et vérifiez que le challenge était frais au moment de l'envoi à CaptchaAI.

Combien coûte la résolution de GeeTest v3 à grande échelle ?

La facturation est basée sur les threads, pas sur le nombre de résolutions. Le plan BASIC ($15/mois, 5 threads) couvre un usage léger ; pour du volume, ADVANCE ($90/mois, 50 threads) ou un palier supérieur traite plusieurs CAPTCHA en parallèle sans surcoût par résolution.


Guides connexes


Maîtrisez les paramètres GeeTest — démarrez avec CaptchaAI.

Les commentaires sont désactivés pour cet article.