Integrations

Oxylabs + CaptchaAI : Intégration du proxy du centre de données

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 ThreadPoolExecutor de 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.

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