Tutorials

Extraction et résolution des paramètres du curseur GeeTest v3

Un curseur GeeTest v3 se résout à partir de deux valeurs, et rien d'autre : gt, l'identifiant statique du site, et challenge, le jeton de session régénéré à chaque affichage. Toute la difficulté tient dans le challenge : il expire en quelques dizaines de secondes, capturez-le et envoyez-le à CaptchaAI sans attendre.

Ce tutoriel couvre trois méthodes d'extraction complémentaires, la résolution du curseur via l'API, puis l'injection de la solution dans le formulaire. Les exemples sont fournis en Python et en JavaScript, directement réutilisables sur vos propres pages.

Les deux paramètres à extraire : gt et challenge

Paramètre Rôle Statique ou dynamique Exemple
gt Identifiant du site (32 caractères hexadécimaux) Statique par site 019924a82c70bb123aae90d483b6a0ed
challenge Jeton de session (32 caractères hexadécimaux) Régénéré à chaque chargement a3f5c8d2e1b04a6789012345678abcdf
api_server Sous-domaine API GeeTest (facultatif) Statique par site api-na.geetest.com

Le gt ne bouge pas d'une requête à l'autre. Le challenge, lui, est régénéré à chaque affichage du CAPTCHA : extrayez-en un neuf pour chaque tentative de résolution. Trois points à garder en tête avant de coder :

  • Le gt s'extrait une seule fois et se met en cache, car il ne change pas.
  • Le challenge se réextrait à chaque tentative, sans exception.
  • Le champ api_server est facultatif : ne l'ajoutez que si la cible s'appuie dessus.

Méthode 1 : intercepter l'appel d'enregistrement

La plupart des intégrations de GeeTest v3 récupèrent le défi depuis un endpoint d'enregistrement appelé au chargement de la page. C'est l'approche la plus fiable : vous lisez gt et challenge directement dans une réponse JSON, sans dépendre du balisage HTML. La réponse ressemble à ceci :

{
  "success": 1,
  "challenge": "a3f5c8d2e1b04a6789012345678abcdf",
  "gt": "019924a82c70bb123aae90d483b6a0ed",
  "new_captcha": true
}

Python (requests)

Une session requests suit les redirections et conserve les cookies, ce qui suffit pour la plupart des pages de connexion. Repérez l'URL d'enregistrement, appelez-la, puis lisez les deux champs :

import requests
import re

session = requests.Session()
html = session.get("https://example.com/login").text

# Find the register endpoint
register_url = re.search(
    r'(https?://[^"\']+(?:register|captcha|geetest)[^"\']*)',
    html
)

if register_url:
    resp = session.get(register_url.group(1)).json()
    gt = resp["gt"]
    challenge = resp["challenge"]
    print(f"gt: {gt}")
    print(f"challenge: {challenge}")

JavaScript (interception réseau avec Puppeteer)

Quand l'appel d'enregistrement est déclenché par du JavaScript, un navigateur headless comme Puppeteer capte la réponse au vol. Écoutez l'événement response et filtrez les URL qui contiennent register ou captcha :

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch();
const page = await browser.newPage();

let geetestParams = {};

page.on('response', async (response) => {
  const url = response.url();
  if (url.includes('register') || url.includes('captcha')) {
    try {
      const json = await response.json();
      if (json.gt && json.challenge) {
        geetestParams = {
          gt: json.gt,
          challenge: json.challenge,
        };
        console.log('Captured GeeTest params:', geetestParams);
      }
    } catch (e) {}
  }
});

await page.goto('https://example.com/login', { waitUntil: 'networkidle2' });
console.log('Final params:', geetestParams);

Méthode 2 : lire les paramètres dans le code source

Certains sites exposent les paramètres directement dans le HTML ou dans des scripts en ligne. Une expression régulière suffit alors à les récupérer, sans requête supplémentaire ni navigateur :

import re

# From data attributes
gt_match = re.search(r'data-gt=["\']([a-f0-9]{32})', html)
challenge_match = re.search(r'data-challenge=["\']([a-f0-9]{32})', html)

# From JavaScript variables
if not gt_match:
    gt_match = re.search(r'gt\s*[=:]\s*["\']([a-f0-9]{32})', html)
if not challenge_match:
    challenge_match = re.search(r'challenge\s*[=:]\s*["\']([a-f0-9]{32})', html)

gt = gt_match.group(1) if gt_match else None
challenge = challenge_match.group(1) if challenge_match else None
print(f"gt={gt}, challenge={challenge}")

Méthode 3 : intercepter le hook initGeetest

GeeTest v3 s'initialise via l'appel initGeetest(). En l'interceptant avant l'exécution des scripts de la page, vous récupérez la configuration complète, gt et challenge compris :

// Puppeteer: inject before page scripts
await page.evaluateOnNewDocument(() => {
  window.__geetestConfig = null;
  const origInit = window.initGeetest;

  Object.defineProperty(window, 'initGeetest', {
    set(fn) {
      this._initGeetest = function(config, callback) {
        window.__geetestConfig = config;
        console.log('GeeTest config:', JSON.stringify(config));
        return fn(config, callback);
      };
    },
    get() { return this._initGeetest; }
  });
});

await page.goto('https://example.com/login', { waitUntil: 'networkidle2' });

const config = await page.evaluate(() => window.__geetestConfig);
// config = { gt: "019924a...", challenge: "a3f5c8d...", product: "bind", ... }

Quelle méthode d'extraction choisir ?

Les trois approches visent le même résultat, mais ne demandent pas le même effort.

  • Commencez par la méthode 1 : stable, elle ne réclame qu'une requête HTTP.
  • Basculez sur la méthode 2 lorsque les valeurs figurent déjà dans le code source.
  • Réservez la méthode 3 aux intégrations qui masquent l'appel réseau derrière du JavaScript.

Résoudre le curseur GeeTest v3 avec CaptchaAI

Envoyez les deux paramètres à CaptchaAI avec la méthode geetest, puis interrogez le résultat jusqu'à obtenir la solution. Réservez cette extraction à vos environnements ou à des cibles autorisées ; si la page traite des données personnelles, limitez la collecte au strict nécessaire (RGPD).

Python

Le script envoie la tâche à in.php, récupère un identifiant, puis interroge res.php toutes les 5 secondes jusqu'à la réponse. La boucle s'arrête dès que le statut passe à 1 :

import requests
import time

API_KEY = "YOUR_API_KEY"

# Submit
resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "geetest",
    "gt": gt,
    "challenge": challenge,
    "pageurl": "https://example.com/login",
    "json": "1",
}).json()

if resp["status"] != 1:
    raise Exception(f"Submit error: {resp['request']}")

task_id = resp["request"]

# Poll
for _ in range(30):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY, "action": "get", "id": task_id, "json": "1"
    }).json()

    if result["status"] == 1:
        solution = result["request"]
        print(f"Solution: {solution}")
        break
    if result["request"] != "CAPCHA_NOT_READY":
        raise Exception(f"Error: {result['request']}")

JavaScript

La logique est identique avec Axios : un POST pour soumettre la tâche, puis un GET en boucle pour interroger le résultat :

const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
  params: {
    key: 'YOUR_API_KEY',
    method: 'geetest',
    gt: geetestParams.gt,
    challenge: geetestParams.challenge,
    pageurl: 'https://example.com/login',
    json: 1,
  }
});
const taskId = submit.data.request;

let solution = null;
for (let i = 0; i < 30; i++) {
  await new Promise(r => setTimeout(r, 5000));
  const poll = await axios.get('https://ocr.captchaai.com/res.php', {
    params: { key: 'YOUR_API_KEY', action: 'get', id: taskId, json: 1 }
  });
  if (poll.data.status === 1) {
    solution = poll.data.request;
    break;
  }
}
console.log('Solution:', solution);

Injecter la solution dans le formulaire

La réponse de CaptchaAI pour GeeTest v3 contient trois champs : challenge, validate et seccode. Injectez-les dans des champs cachés avant de soumettre le formulaire :

# solution is a pipe-delimited string or JSON object
# Parse and inject into the form
import json

sol = json.loads(solution) if isinstance(solution, str) else solution

driver.execute_script("""
    const form = document.querySelector('form');
    function addHidden(name, value) {
        let input = form.querySelector(`input[name="${name}"]`);
        if (!input) {
            input = document.createElement('input');
            input.type = 'hidden';
            input.name = name;
            form.appendChild(input);
        }
        input.value = value;
    }
    addHidden('geetest_challenge', arguments[0]);
    addHidden('geetest_validate', arguments[1]);
    addHidden('geetest_seccode', arguments[2]);
""", sol["challenge"], sol["validate"], sol["seccode"])

Dépannage

La plupart des échecs viennent d'un challenge expiré ou d'un gt copié d'un autre site. Le tableau suivant regroupe les cas les plus fréquents et leur correctif :

Problème Cause Correctif
ERROR_BAD_PARAMETERS gt ou challenge absent Les deux sont obligatoires ; extrayez de nouvelles valeurs
challenge périmé Le jeton de défi a expiré Extrayez un nouveau challenge juste avant l'envoi
Mauvaise valeur gt Copiée depuis un autre site Le gt est propre à chaque site ; réextrayez-le sur la cible
Solution refusée par le site Le défi a expiré pendant la résolution Réduisez le délai entre l'extraction et la soumission
CAPCHA_NOT_READY en boucle La résolution est encore en cours Continuez d'interroger res.php toutes les 5 s, sans raccourcir l'intervalle

FAQ

Les questions ci-dessous reviennent le plus souvent lors d'une première intégration de GeeTest v3.

Faut-il piloter un navigateur pour extraire le challenge ?

Pas toujours. Si le défi provient d'un appel d'enregistrement (méthode 1), une simple requête HTTP avec requests suffit. Sinon, passez par un navigateur headless comme Puppeteer.

Pourquoi le challenge change-t-il à chaque chargement ?

C'est un jeton de session à usage unique : GeeTest en émet un neuf à chaque affichage pour empêcher le rejeu. Seul le gt, l'identifiant du site, reste stable.

CaptchaAI prend-il en charge GeeTest v4 ?

Pas encore : seul GeeTest v3 est pris en charge. GeeTest v4 est annoncé comme à venir, sans date publique.

Combien de temps un défi GeeTest reste-t-il exploitable ?

En général 60 à 120 secondes. Envoyez le challenge à CaptchaAI dans la foulée pour éviter qu'il n'expire avant la validation.

Résolvez vos CAPTCHA GeeTest v3 avec CaptchaAI

Créez votre compte et récupérez votre clé API sur captchaai.com, puis lancez votre première résolution GeeTest v3 avec les scripts ci-dessus.

Guides associés

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