Tutoriales

Inyección de tokens GeeTest en marcos de automatización de navegadores

GeeTest v3 devuelve tres valores después de resolver: geetest_challenge, geetest_validate y geetest_seccode. Inyectarlos correctamente en una sesión de automatización del navegador requiere comprender dónde los espera el sitio: campos de formulario ocultos, devoluciones de llamada de JavaScript o cargas útiles XHR. Aquí se explica cómo hacerlo en cada marco principal.

Lo que estás inyectando

CaptchaAI devuelve un resultado de tres partes:

{
  "geetest_challenge": "a1b2c3d4e5...modified_challenge",
  "geetest_validate": "abc123def456_validate",
  "geetest_seccode": "abc123def456_validate|jordan"
}

Se deben inyectar los tres valores. Faltar alguno provoca un error de verificación.

Paso 1: extraer parámetros y resolver

Común a todos los marcos: extraiga gt y challenge, luego resuelva con CaptchaAI:

import requests
import time

def solve_geetest(gt, challenge, page_url):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "geetest",
        "gt": gt,
        "challenge": challenge,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]  # Returns dict with three values
    raise TimeoutError("GeeTest solve timed out")

Paso 2: inyectar en Playwright (Python)

Extraer parámetros

from playwright.sync_api import sync_playwright

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

    # Capture GeeTest registration response
    geetest_data = {}
    def capture_geetest(response):
        if "register" in response.url and response.status == 200:
            try:
                data = response.json()
                if "gt" in data and "challenge" in data:
                    geetest_data.update(data)
            except Exception:
                pass

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

    gt = geetest_data["gt"]
    challenge = geetest_data["challenge"]

Inyectar solución

# Solve con CaptchaAI
solution = solve_geetest(gt, challenge, page.url)

# Method 1: Set hidden form fields
page.evaluate(f"""
  const fields = {{
    'geetest_challenge': '{solution["geetest_challenge"]}',
    'geetest_validate': '{solution["geetest_validate"]}',
    'geetest_seccode': '{solution["geetest_seccode"]}'
  }};
  for (const [name, value] of Object.entries(fields)) {{
    let input = document.querySelector(`input[name="${{name}}"]`);
    if (!input) {{
      input = document.createElement('input');
      input.type = 'hidden';
      input.name = name;
      document.querySelector('form').appendChild(input);
    }}
    input.value = value;
  }}
""")

# Submit the form
page.click("#submit-button")

Método 2: activar la devolución de llamada de GeeTest

Algunos sitios utilizan la devolución de llamada de JavaScript de GeeTest en lugar de campos de formulario:

page.evaluate(f"""
  // Find the GeeTest captcha object
  if (window.captchaObj) {{
    // Simulate a successful solve
    const result = {{
      geetest_challenge: '{solution["geetest_challenge"]}',
      geetest_validate: '{solution["geetest_validate"]}',
      geetest_seccode: '{solution["geetest_seccode"]}'
    }};

    // Override getValidate to return our solution
    window.captchaObj.getValidate = function() {{ return result; }};

    // Trigger the success callback
    const successEvent = new Event('geetest_success');
    document.dispatchEvent(successEvent);
  }}
""")

Paso 3: Inyectar en Puppeteer (JavaScript)

const puppeteer = require('puppeteer');

async function solveAndInject() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();

  // Capture GeeTest params
  let gt, challenge;
  page.on('response', async (response) => {
    if (response.url().includes('register') && response.status() === 200) {
      try {
        const data = await response.json();
        if (data.gt && data.challenge) {
          gt = data.gt;
          challenge = data.challenge;
        }
      } catch (e) {}
    }
  });

  await page.goto('https://staging.example.com/qa-login');
  await page.waitForSelector('.geetest_holder');

  // Solve con CaptchaAI (implementation from earlier)
  const solution = await solveCaptcha(gt, challenge, page.url());

  // Inject the three values
  await page.evaluate((sol) => {
    // Set hidden inputs
    const form = document.querySelector('form');
    ['geetest_challenge', 'geetest_validate', 'geetest_seccode'].forEach(name => {
      let input = document.querySelector(`input[name="${name}"]`);
      if (!input) {
        input = document.createElement('input');
        input.type = 'hidden';
        input.name = name;
        form.appendChild(input);
      }
      input.value = sol[name];
    });
  }, solution);

  await page.click('#submit-button');
}

Paso 4: inyectar selenio (Python)

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-login")

# Wait for GeeTest widget
WebDriverWait(driver, 15).until(
    EC.presence_of_element_located((By.CLASS_NAME, "geetest_holder"))
)

# Extract gt and challenge from the page
gt = driver.execute_script(
    "return document.querySelector('[data-gt]')?.dataset.gt"
)
challenge = driver.execute_script(
    "return document.querySelector('[data-challenge]')?.dataset.challenge"
)

# Solve con CaptchaAI
solution = solve_geetest(gt, challenge, driver.current_url)

# Inject via JavaScript
driver.execute_script(f"""
    var fields = {{
        'geetest_challenge': '{solution["geetest_challenge"]}',
        'geetest_validate': '{solution["geetest_validate"]}',
        'geetest_seccode': '{solution["geetest_seccode"]}'
    }};
    var form = document.querySelector('form');
    for (var name in fields) {{
        var input = document.querySelector('input[name="' + name + '"]');
        if (!input) {{
            input = document.createElement('input');
            input.type = 'hidden';
            input.name = name;
            form.appendChild(input);
        }}
        input.value = fields[name];
    }}
""")

driver.find_element(By.ID, "submit-button").click()

Manejo de envíos basados en XHR

Algunos sitios envían los resultados de GeeTest a través de XHR en lugar del formulario POST. Interceptar y modificar la solicitud:

# Playwright: Intercept the XHR and inject values
def handle_route(route):
    if "login" in route.request.url and route.request.method == "POST":
        # Modify the POST data to include our solution
        post_data = route.request.post_data
        # Add GeeTest values to the request
        route.continue_(post_data=modified_data)
    else:
        route.continue_()

page.route("**/api/login**", handle_route)

Solución de problemas

Problema causa Solución
"La validación de GeeTest falló" Falta uno de los tres valores. Verifique que los tres valores estén inyectados
El desafío expiró antes de la inyección Demasiado tiempo entre la extracción y la resolución Extrae y resuelve en rápida sucesión
El formulario se envía pero los valores no están incluidos. Nombres de campos o selector de formulario incorrectos Inspeccione el formulario real para encontrar los nombres correctos.
Devolución de llamada no activada El sitio utiliza un nombre de devolución de llamada personalizado Encuentra la devolución de llamada en las opciones de initGeetest
Valores inyectados pero el widget aún se muestra Estado del widget no actualizado Activar la devolución de llamada exitosa mediante programación

Preguntas frecuentes

¿Necesito ocultar visualmente el widget GeeTest después de la inyección?

No. El estado visual del widget no afecta el envío del formulario. Mientras los tres valores estén en los datos del formulario, el servidor los valida independientemente de la apariencia del widget.

¿Puedo inyectar valores de GeeTest sin un navegador?

Sí, si el sitio acepta un POST HTTP directo con los tres valores. Intercepte el punto final de envío del formulario y envíe los valores a través de requests o cualquier cliente HTTP.

¿Por qué GeeTest utiliza tres valores separados en lugar de un token?

Los tres valores tienen diferentes propósitos: geetest_challenge rastrea la sesión, geetest_validate demuestra que el desafío se resolvió y geetest_seccode proporciona un hash para la detección de manipulaciones.

Artículos relacionados

Próximos pasos

Inyecte soluciones GeeTest en cualquier marco:obtenga su clave API CaptchaAIy empieza a resolver.

Los comentarios están deshabilitados para este artículo.