Reference

Guide complet : Résolution de CAPTCHA, des bases à la production

Tout ce dont vous avez besoin pour passer de votre première résolution CAPTCHA à un pipeline de production.


Partie 1 : Comprendre les CAPTCHA

Qu'est-ce qu'un CAPTCHA ?

Un CAPTCHA (test de Turing public complètement automatisé pour distinguer les ordinateurs des humains) est un défi conçu pour bloquer l'accès automatisé tout en permettant aux utilisateurs humains de passer.

Types que vous rencontrerez

Tapez Exemples Défi
Texte/Image Lettres déformées, expressions mathématiques Tapez ce que vous voyez
Case à cocher reCAPTCHA v2 Cliquez sur la case à cocher, résolvez éventuellement la grille d'images
Invisibles reCAPTCHA v3, Tourniquet Aucune interaction avec l'utilisateur – notation comportementale
Interactif Diapositive GeeTest, grille BLS Faites glisser, cliquez ou commandez des éléments

Pourquoi les sites utilisent des CAPTCHA

  • Empêcher la création automatisée de comptes
  • Bloquer le scraping et la collecte de données
  • Arrêtez le spam dans les formulaires et les commentaires
  • Accès à l'API à débit limité

Partie 2 : Comment fonctionnent les services de résolution de CAPTCHA

Le flux

Your Code  →  Submit CAPTCHA to API  →  Solving Service  →  Return Token/Text  →  Your Code Injects Result

Étape par étape

  1. Extraire les paramètres CAPTCHA de la page cible (sitekey, challenge, image)
  2. Soumettre les paramètres à l'API de résolution
  3. Sondage pour le résultat (jeton ou texte)
  4. Injecter le résultat dans la page
  5. Envoyer le formulaire

Partie 3 : Configuration de CaptchaAI

Installer les dépendances

pip install requests

Classe de solveur de base

import time
import requests

class CaptchaAI:
    BASE = "https://ocr.captchaai.com"

    def __init__(self, api_key):
        self.api_key = api_key

    def submit(self, params):
        params["key"] = self.api_key
        params["json"] = 1
        resp = requests.post(f"{self.BASE}/in.php", data=params)
        data = resp.json()
        if data["status"] != 1:
            raise Exception(f"Submit failed: {data['request']}")
        return data["request"]

    def get_result(self, task_id, timeout=300, interval=5, initial_wait=10):
        time.sleep(initial_wait)
        deadline = time.time() + timeout
        while time.time() < deadline:
            resp = requests.get(
                f"{self.BASE}/res.php",
                params={
                    "key": self.api_key,
                    "action": "get",
                    "id": task_id,
                    "json": 1,
                },
            ).json()
            if resp["request"] == "CAPCHA_NOT_READY":
                time.sleep(interval)
                continue
            if resp["status"] == 1:
                return resp["request"]
            raise Exception(f"Solve failed: {resp['request']}")
        raise TimeoutError("Solve timed out")

    def solve(self, params, **kwargs):
        task_id = self.submit(params)
        return self.get_result(task_id, **kwargs)

    def balance(self):
        resp = requests.get(
            f"{self.BASE}/res.php",
            params={"key": self.api_key, "action": "getbalance"},
        )
        return float(resp.text)

Partie 4 : Résoudre chaque type de CAPTCHA

reCAPTCHA v2

solver = CaptchaAI("YOUR_API_KEY")
token = solver.solve({
    "method": "userrecaptcha",
    "googlekey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    "pageurl": "https://example.com/login",
})

reCAPTCHA v3

token = solver.solve({
    "method": "userrecaptcha",
    "googlekey": "SITE_KEY",
    "pageurl": "https://example.com",
    "version": "v3",
    "action": "submit",
}, initial_wait=20)

Cloudflare Turnstile

token = solver.solve({
    "method": "turnstile",
    "sitekey": "0x4AAAAAAAC3a...",
    "pageurl": "https://example.com",
})

GeeTest v3

result = solver.solve({
    "method": "geetest",
    "gt": "GT_VALUE",
    "challenge": "CHALLENGE_VALUE",
    "pageurl": "https://example.com",
})

Image/OCR

import base64

with open("captcha.png", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode()

text = solver.solve({
    "method": "base64",
    "body": img_b64,
    "numeric": "1",
    "minLen": "4",
    "maxLen": "6",
})

Partie 5 : Extraction des paramètres CAPTCHA

Clé de site reCAPTCHA

from selenium import webdriver
from selenium.webdriver.common.by import By

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

# Method 1: From div attribute
sitekey = driver.find_element(
    By.CSS_SELECTOR, "[data-sitekey]"
).get_attribute("data-sitekey")

# Method 2: From iframe URL
import re
iframe = driver.find_element(By.CSS_SELECTOR, "iframe[src*='recaptcha']")
src = iframe.get_attribute("src")
sitekey = re.search(r"k=([^&]+)", src).group(1)

Clé du site du tourniquet

sitekey = driver.find_element(
    By.CSS_SELECTOR, "[data-sitekey], .cf-turnstile"
).get_attribute("data-sitekey")

Paramètres GeeTest

import json

gt_data = driver.execute_script("""
    return {
        gt: document.querySelector('[data-gt]')?.getAttribute('data-gt'),
        challenge: document.querySelector('[data-challenge]')?.getAttribute('data-challenge')
    };
""")

Partie 6 : Solutions d'injection

Basé sur des jetons (reCAPTCHA, Turnstile)

driver.execute_script(f"""
    document.querySelector('[name="g-recaptcha-response"]').value = '{token}';
    document.querySelector('[name="cf-turnstile-response"]').value = '{token}';
""")

Pour les rappels

driver.execute_script(f"""
    if (typeof ___grecaptcha_cfg !== 'undefined') {{
        Object.keys(___grecaptcha_cfg.clients).forEach(function(key) {{
            var client = ___grecaptcha_cfg.clients[key];
            // Find and call the callback
        }});
    }}
""")

Partie 7 : Gestion des erreurs

Logique de nouvelle tentative

def solve_with_retry(solver, params, max_retries=3):
    for attempt in range(max_retries):
        try:
            return solver.solve(params)
        except Exception as e:
            error = str(e)
            if "ZERO_BALANCE" in error:
                raise  # Don't retry — need funds
            if "UNSOLVABLE" in error:
                print(f"Attempt {attempt + 1} failed, retrying...")
                continue
            raise
    raise Exception(f"Failed after {max_retries} attempts")

Surveillance du solde

def check_balance_before_solve(solver, min_balance=0.10):
    balance = solver.balance()
    if balance < min_balance:
        raise Exception(f"Low balance: ${balance:.2f}")
    return balance

Partie 8 : Modèles de production

Regroupement de connexions

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session():
    session = requests.Session()
    retry = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503])
    adapter = HTTPAdapter(max_retries=retry, pool_connections=10, pool_maxsize=20)
    session.mount("https://", adapter)
    return session

Résolution simultanée

from concurrent.futures import ThreadPoolExecutor, as_completed

def solve_batch(solver, captcha_list, max_workers=5):
    results = {}
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {
            executor.submit(solver.solve, params): url
            for url, params in captcha_list
        }
        for future in as_completed(futures):
            url = futures[future]
            try:
                results[url] = future.result()
            except Exception as e:
                results[url] = f"ERROR: {e}"
    return results

Limitation du débit

import threading

class RateLimiter:
    def __init__(self, max_per_second=10):
        self.interval = 1.0 / max_per_second
        self.lock = threading.Lock()
        self.last_call = 0

    def wait(self):
        with self.lock:
            now = time.time()
            wait_time = self.last_call + self.interval - now
            if wait_time > 0:
                time.sleep(wait_time)
            self.last_call = time.time()

Partie 9 : Surveillance

Journalisation

import logging

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger("captcha")

def solve_logged(solver, params):
    start = time.time()
    logger.info(f"Submitting {params.get('method')} CAPTCHA")
    try:
        result = solver.solve(params)
        elapsed = time.time() - start
        logger.info(f"Solved in {elapsed:.1f}s")
        return result
    except Exception as e:
        elapsed = time.time() - start
        logger.error(f"Failed after {elapsed:.1f}s: {e}")
        raise

Suivi des métriques

class SolveMetrics:
    def __init__(self):
        self.total = 0
        self.success = 0
        self.failures = 0
        self.total_time = 0.0

    def record(self, success, elapsed):
        self.total += 1
        self.total_time += elapsed
        if success:
            self.success += 1
        else:
            self.failures += 1

    def summary(self):
        rate = (self.success / self.total * 100) if self.total else 0
        avg = (self.total_time / self.total) if self.total else 0
        return {
            "total": self.total,
            "success_rate": f"{rate:.1f}%",
            "avg_time": f"{avg:.1f}s",
        }

Partie 10 : Liste de contrôle

Étape Tâche
1 Installez requests et obtenez la clé API
2 Identifiez le type CAPTCHA sur la page cible
3 Extraire la clé du site/parameters
4 Soumettre à CaptchaAI avec la bonne méthode
5 Sondage avec le bon timing
6 Injecter le jeton et soumettre le formulaire
7 Ajouter une logique de nouvelle tentative pour la production
8 Surveiller le taux de réussite et les coûts
9 Évoluez avec le pooling de connexions et la concurrence

FAQ

Combien coûte la résolution de CAPTCHA ?

Le prix varie selon le type. Consultez votre tableau de bord pour connaître les tarifs actuels. Les CAPTCHA d’image sont les moins chers ; Les types basés sur des jetons coûtent plus cher.

Quel type de CAPTCHA est le plus rapide à résoudre ?

Les CAPTCHA Image/OCR se résolvent en 5 à 15 secondes. Le tourniquet se résout rapidement grâce à un taux de réussite de 100 %. reCAPTCHA v3 peut prendre 20 à 30 secondes.

Puis-je résoudre les CAPTCHA sans navigateur ?

Oui, pour les CAPTCHA basés sur des jetons, vous n'avez besoin que de la clé du site et de l'URL de la page — aucun navigateur n'est requis. Les CAPTCHA d’image n’ont besoin que des données d’image.

Comment gérer l’expiration des jetons ?

Résolvez les CAPTCHA juste avant d’en avoir besoin. Les jetons reCAPTCHA expirent dans environ 120 secondes, Turnstile dans environ 300 secondes. Ne pré-résolvez pas en masse.


Guides connexes


Des bases à la production dans un seul guide —commencer par CaptchaAI.

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