L'échec le plus fréquent d'une intégration Oxylabs + CaptchaAI ne vient pas de la résolution ; il vient de l'IP. Le token est valide, mais le formulaire le refuse parce que le pool a changé d'adresse entre le GET et le POST : une session sticky règle ce cas précis.
Le montage tient en trois choix : l'endpoint Oxylabs adapté à la cible, une session HTTP qui garde la même IP jusqu'à l'envoi du formulaire, et un nombre de threads aligné sur vos workers. Datacenter ou résidentiel se tranche ensuite sur un chiffre : la part de pages qui présentent un défi.
Ce que règle le proxy, ce que règle CaptchaAI
Le proxy agit sur la réputation réseau : géolocalisation, type d'IP, historique. Le solveur agit sur le défi lui-même, en produisant une valeur g-recaptcha-response valide pour le couple sitekey + URL.
- Oxylabs décide d'où part la requête et si la même IP est réutilisée.
- CaptchaAI prend en charge reCAPTCHA v2 et v3, Cloudflare Turnstile et Challenge, GeeTest v3, les CAPTCHA image/OCR et les grilles d'images ; CaptchaFox (bêta), Friendly Captcha (bêta) et Lemin (bêta) en complément.
- Votre code envoie le token depuis la même IP et la même session que la page qui l'a demandé.
Choisir la gamme de proxys Oxylabs selon la cible
Les caractéristiques ci-dessous sont celles publiées par le fournisseur. Plus l'IP ressemble à celle d'un particulier, moins vous voyez de défis, mais plus le gigaoctet coûte cher.
| Gamme | Volume d'IP annoncé | Vitesse | Cas d'usage typique |
|---|---|---|---|
| Proxys datacenter | 2 M+ | Très rapide | Gros volumes, priorité au débit |
| Proxys résidentiels | 100 M+ | Moyenne | Sites sensibles aux CAPTCHA |
| Proxys ISP | Qualité résidentielle | Rapide | E-commerce, réseaux sociaux |
| Proxys mobiles | 20 M+ | Lente | Cibles spécifiquement mobiles |
| SERP Scraper API | Service géré | Rapide | Résultats Google/Bing |
Intégration Python : de la requête proxifiée au token
Requêtes via un proxy rotatif
fetch_page() passe par le pool Oxylabs, avec un ciblage pays facultatif via le suffixe -cc-. solve_recaptcha() envoie le sitekey et l'URL à CaptchaAI, puis interroge le résultat toutes les 5 secondes.
import requests
import time
OXYLABS_USER = "customer-USERNAME"
OXYLABS_PASS = "PASSWORD"
OXYLABS_ENDPOINT = "pr.oxylabs.io:7777"
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
# Residential rotating proxy
proxies = {
"http": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
"https": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
}
def fetch_page(url, country=None):
"""Fetch page through Oxylabs proxy."""
user = OXYLABS_USER
if country:
user += f"-cc-{country}"
proxy = {
"http": f"http://{user}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
"https": f"http://{user}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
}
return requests.get(
url,
proxies=proxy,
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36"
},
timeout=30,
)
def solve_recaptcha(site_url, sitekey):
"""Solve via CaptchaAI."""
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": site_url,
"json": 1,
})
data = resp.json()
if data["status"] != 1:
raise Exception(f"Submit: {data['request']}")
task_id = data["request"]
for _ in range(60):
time.sleep(5)
resp = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY,
"action": "get",
"id": task_id,
"json": 1,
})
data = resp.json()
if data["request"] == "CAPCHA_NOT_READY":
continue
if data["status"] == 1:
return data["request"]
raise Exception(f"Solve: {data['request']}")
raise TimeoutError("Timeout")
Le timeout=30 est volontairement large : une IP résidentielle ajoute quelques centaines de millisecondes. La boucle s'arrête après 60 tours, soit cinq minutes ; au-delà, relancez la tâche.
Sessions sticky : garder la même IP jusqu'à l'envoi du formulaire
Le suffixe -sessid- fige l'IP pour la durée de la session, dix minutes par défaut : chargez la page, faites résoudre le défi, puis postez g-recaptcha-response depuis la même adresse.
def get_oxylabs_sticky_proxy(session_id, country=None):
"""Create Oxylabs sticky session (same IP)."""
user = OXYLABS_USER + f"-sessid-{session_id}"
if country:
user += f"-cc-{country}"
proxy_url = f"http://{user}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}"
return {"http": proxy_url, "https": proxy_url}
# CAPTCHA workflow with sticky IP
import random, string
session = "".join(random.choices(string.ascii_lowercase, k=8))
proxy = get_oxylabs_sticky_proxy(session, country="us")
# All requests use the same IP
resp = requests.get("https://target.com/form", proxies=proxy)
# ... solve CAPTCHA ...
resp = requests.post("https://target.com/submit", proxies=proxy, data={
"g-recaptcha-response": token,
})
Générez un identifiant de session par parcours, jamais un identifiant global : deux parcours simultanés sur une même IP se remarquent bien plus vite.
Web Scraper API d'Oxylabs : rendu côté fournisseur, résolution côté CaptchaAI
Quand la cible exige un rendu JavaScript complet, la Web Scraper API d'Oxylabs renvoie le HTML déjà rendu. Elle ne résout pas les CAPTCHA : si un sitekey apparaît dans la réponse, c'est à votre code de le transmettre à CaptchaAI.
def scrape_with_oxylabs_api(url):
"""Use Oxylabs Web Scraper API for rendering, CaptchaAI for CAPTCHAs."""
resp = requests.post(
"https://realtime.oxylabs.io/v1/queries",
auth=(OXYLABS_USER, OXYLABS_PASS),
json={
"source": "universal",
"url": url,
"render": "html",
"browser_instructions": [
{"type": "wait", "wait_time_s": 3},
],
},
)
result = resp.json()
html = result["results"][0]["content"]
# Check for CAPTCHA in rendered HTML
import re
sitekey_match = re.search(r'data-sitekey="([^"]+)"', html)
if sitekey_match:
sitekey = sitekey_match.group(1)
token = solve_recaptcha(url, sitekey)
return {"html": html, "captcha_solved": True, "token": token}
return {"html": html, "captcha_solved": False}
L'expression régulière suffit pour un attribut data-sitekey classique. Quand la clé est injectée en JavaScript, cherchez le paramètre render= du script reCAPTCHA.
Datacenter ou résidentiel : la règle de décision
L'arbitrage est financier avant d'être technique : une IP datacenter coûte peu, répond vite et déclenche plus de défis ; une IP résidentielle en déclenche moins, mais se facture au gigaoctet.
# Datacenter: Fast but higher CAPTCHA rate
DC_PROXY = {
"http": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@dc.pr.oxylabs.io:10000",
"https": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@dc.pr.oxylabs.io:10000",
}
# Residential: Slower but lower CAPTCHA rate
RES_PROXY = {
"http": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@pr.oxylabs.io:7777",
"https": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@pr.oxylabs.io:7777",
}
def smart_proxy_selection(url, captcha_sensitive=True):
"""Pick proxy type based on target site sensitivity."""
if captcha_sensitive:
return RES_PROXY # Less likely to trigger CAPTCHA
return DC_PROXY # Faster, CaptchaAI handles any CAPTCHAs
Décidez par domaine cible. Mesurez ce taux sur 200 à 500 requêtes, puis comparez le surcoût du résidentiel et le coût des threads.
- Moins de 10 % de pages avec défi : restez en datacenter.
- Entre 10 % et 40 % : testez le proxy ISP.
- Au-delà : résidentiel avec sessions sticky, CaptchaAI pour le reste.
Monter en charge : workers Oxylabs et threads CaptchaAI
Le pipeline ci-dessous traite plusieurs URL en parallèle, chacune avec sa session sticky.
from concurrent.futures import ThreadPoolExecutor, as_completed
def process_url(url):
session = "".join(random.choices(string.ascii_lowercase, k=8))
proxy = get_oxylabs_sticky_proxy(session, country="us")
try:
resp = requests.get(url, proxies=proxy, timeout=30)
import re
match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if match:
token = solve_recaptcha(url, match.group(1))
return {"url": url, "status": "solved"}
return {"url": url, "status": "no_captcha"}
except Exception as e:
return {"url": url, "status": "error", "error": str(e)}
urls = ["https://site1.com", "https://site2.com", "https://site3.com"]
with ThreadPoolExecutor(max_workers=5) as executor:
futures = {executor.submit(process_url, u): u for u in urls}
for future in as_completed(futures):
print(future.result())
max_workers=5 doit rester aligné sur le nombre de threads de votre plan : un thread correspond à un CAPTCHA en cours de résolution et se libère dès que le token part. La facturation porte sur ces threads simultanés, pas sur le nombre de résolutions.
- BASIC ($15/mois, 5 threads) : exactement le
ThreadPoolExecutorde l'exemple. - STANDARD ($30/mois, 15 threads) : trois processus menant chacun cinq parcours.
- ADVANCE ($90/mois, 50 threads) : volumes soutenus, plusieurs domaines en parallèle.
En pratique : veille tarifaire e-commerce depuis l'Europe
Une équipe relève chaque matin le prix de 3 000 fiches produit chez des marchands français et belges. Les pages catégorie passent en datacenter ; leur propre espace revendeur affiche un reCAPTCHA v2 à chaque nouvelle IP.
Le montage qui tient : datacenter pour le catalogue, session sticky résidentielle -cc-fr pour la partie authentifiée, CaptchaAI sur ce seul flux. Avec des workers en eu-west-3 (Paris) ou chez OVHcloud, le temps total reste dominé par la résolution.
Côté conformité, ne collectez que les champs utiles — référence, prix, horodatage — et n'archivez pas de pages authentifiées dans vos logs. Le RGPD s'applique aussi à ces caches de HTML.
Dépannage
| Symptôme | Cause probable | Correctif |
|---|---|---|
| 403 renvoyé par la cible | IP du pool déjà signalée | Forcez une rotation ou passez au résidentiel |
| Échec d'authentification proxy | Endpoint incorrect | Datacenter : dc.pr.oxylabs.io:10000 ; résidentiel : pr.oxylabs.io:7777 |
| L'IP change en cours de parcours | Session sticky expirée (10 min) | Générez un nouveau sessid avant de résoudre |
| Un défi sur chaque page | IP datacenter identifiée | Passez en résidentiel ou en proxy ISP |
| Token refusé par le formulaire | Token posté depuis une autre IP | Réutilisez la session sticky du GET pour le POST |
FAQ
Faut-il une session sticky pour que le token reCAPTCHA soit accepté ?
Oui, dans la quasi-totalité des cas : si le pool fait tourner l'IP entre le GET et le POST, le serveur rejette l'envoi. Utilisez -sessid- pour tout parcours multi-étapes.
Combien de threads CaptchaAI prévoir pour cinq workers en parallèle ?
Cinq threads suffisent tant que chaque worker ne traite qu'un défi à la fois, soit le plan BASIC ($15/mois, 5 threads). Prévoyez une marge si vos parcours enchaînent plusieurs défis.
hCaptcha est-il pris en charge derrière un proxy Oxylabs ?
Non : hCaptcha et FunCaptcha (Arkose Labs) ne sont pas pris en charge, quel que soit le proxy, et GeeTest v4 est annoncé comme à venir. Restent reCAPTCHA v2 et v3, Turnstile, Cloudflare Challenge, GeeTest v3, image/OCR et grilles.
Le trafic proxy fausse-t-il la mesure du temps de résolution ?
Non : mesurez séparément la durée de la requête HTTP à travers Oxylabs et l'intervalle entre in.php et le token renvoyé par res.php.
Guides connexes
Associez l'infrastructure proxy d'Oxylabs à la résolution CaptchaAI — récupérez votre clé API.