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
- Extraire les paramètres CAPTCHA de la page cible (sitekey, challenge, image)
- Soumettre les paramètres à l'API de résolution
- Sondage pour le résultat (jeton ou texte)
- Injecter le résultat dans la page
- 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.