Les applications à page unique chargent reCAPTCHA de manière dynamique : le widget n'existe pas dans le HTML initial. Un formulaire de connexion React restitue le CAPTCHA uniquement lorsque le composant est monté. Une page de paiement Vue charge reCAPTCHA après que l'utilisateur a cliqué sur "Passer la commande". Le scraping traditionnel des sources de page les manque complètement. Voici comment détecter et résoudre les reCAPTCHA chargés dynamiquement.
Pourquoi les SPA sont différents
| Page traditionnelle | SPA |
|---|---|
| Script reCAPTCHA dans le HTML initial | Script injecté après changement de route |
| Le widget s'affiche au chargement de la page | Le widget s'affiche lors du montage du composant |
| Clé du site dans la source de la page | Clé de site dans le bundle JavaScript |
| Formulaire soumis via POST | Le formulaire est soumis via XHR/fetch |
Dans un SPA, le widget reCAPTCHA peut ne pas exister jusqu'à ce qu'une action spécifique de l'utilisateur le déclenche. Votre automatisation doit attendre que le widget apparaisse.
Détection du widget reCAPTCHA
Attendez l'élément
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://example.com/login")
# SPA may need a click or navigation to trigger reCAPTCHA
page.click("#show-login-form")
# Wait for reCAPTCHA iframe to appear
recaptcha_frame = page.wait_for_selector(
"iframe[src*='recaptcha']",
timeout=15000
)
print("reCAPTCHA detected:", recaptcha_frame.get_attribute("src"))
Extraire la clé du site
La clé du site peut se trouver à plusieurs emplacements dans un SPA :
# Method 1: From the iframe src
iframe_src = recaptcha_frame.get_attribute("src")
# src contains: ...?k=6LcR_RsTAAAAADge...
import re
match = re.search(r'[?&]k=([^&]+)', iframe_src)
site_key = match.group(1) if match else None
# Method 2: From data-sitekey attribute
site_key = page.eval_on_selector(
"[data-sitekey]",
"el => el.getAttribute('data-sitekey')"
)
# Method 3: From JavaScript bundle (last resort)
site_key = page.evaluate("""
() => {
// Check for grecaptcha render calls
const scripts = document.querySelectorAll('script');
for (const s of scripts) {
const match = s.textContent.match(/sitekey['":\s]+(['"])(6L[^'"]+)\\1/);
if (match) return match[2];
}
return null;
}
""")
Résoudre le reCAPTCHA
Une fois que vous avez la clé du site, soumettez-la à CaptchaAI :
import requests
import time
def solve_recaptcha(site_key, page_url):
# Submit task
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1
})
task_id = resp.json()["request"]
# Poll for result
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"]
raise TimeoutError("Solve timed out")
Injection du jeton dans un SPA
Les SPA ne soumettent pas de formulaires traditionnels. Vous devez injecter le jeton là où l'application l'attend.
Méthode 1 : définir la zone de texte masquée
token = solve_recaptcha(site_key, "https://example.com/login")
# Inject into the g-recaptcha-response textarea
page.evaluate(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
""")
# Submit the form
page.click("#login-button")
Méthode 2 : déclencher le rappel
De nombreuses implémentations de SPA reCAPTCHA utilisent une fonction de rappel :
# Find the callback function name
callback = page.evaluate("""
() => {
const widget = document.querySelector('.g-recaptcha');
return widget?.getAttribute('data-callback') || null;
}
""")
# Call it with the token
if callback:
page.evaluate(f"window['{callback}']('{token}')")
else:
# Try the default grecaptcha callback
page.evaluate(f"""
if (window.grecaptcha) {{
// Set the response and trigger verification
document.getElementById('g-recaptcha-response').value = '{token}';
// Find and call any registered callbacks
const form = document.querySelector('form');
if (form) form.dispatchEvent(new Event('submit'));
}}
""")
Méthode 3 : Intercepter le XHR (JavaScript / Puppeteer)
const puppeteer = require('puppeteer');
async function solveRecaptchaInSPA() {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
// Intercept the API call and inject the token
await page.setRequestInterception(true);
page.on('request', request => {
if (request.url().includes('/api/login')) {
const postData = JSON.parse(request.postData() || '{}');
// Token already set via page.evaluate — let it pass
request.continue();
} else {
request.continue();
}
});
await page.goto('https://example.com/login');
await page.waitForSelector('[data-sitekey]');
const siteKey = await page.$eval(
'[data-sitekey]',
el => el.getAttribute('data-sitekey')
);
// Solve with CaptchaAI (implementation omitted — same as Python)
const token = await solveCaptcha(siteKey, page.url());
// Inject token and trigger callback
await page.evaluate((t) => {
document.getElementById('g-recaptcha-response').value = t;
const callback = document.querySelector('.g-recaptcha')
?.getAttribute('data-callback');
if (callback && window[callback]) {
window[callback](t);
}
}, token);
}
Modèles spécifiques au framework
Réagir (réagir-google-recaptcha)
Les applications React utilisent souvent le package react-google-recaptcha. Le composant restitue de manière asynchrone :
# Wait for React to mount the component
page.wait_for_selector(".g-recaptcha", state="attached")
# The sitekey is in the rendered div's data attribute
site_key = page.eval_on_selector(
".g-recaptcha", "el => el.dataset.sitekey"
)
Vue (vue-recaptcha)
# Vue may use v-if to conditionally render
# Navigate or interact to trigger the condition
page.click("#proceed-to-checkout")
page.wait_for_selector("iframe[src*='recaptcha']")
Angulaire
# Angular apps may lazy-load reCAPTCHA modules
# Wait for the specific Angular component
page.wait_for_selector("re-captcha, app-recaptcha, [data-sitekey]")
Gestion des changements d'itinéraire
Les SPA réutilisent la page – la navigation se fait sans rechargement complet :
# Listen for reCAPTCHA appearing after SPA navigation
page.goto("https://example.com")
# Navigate within the SPA
page.click("a[href='/login']")
# The URL changed but no page reload happened
# Wait for the CAPTCHA to render in the new "page"
page.wait_for_selector("iframe[src*='recaptcha']", timeout=10000)
Dépannage
| Problème | Parce que | Corriger |
|---|---|---|
Zone de texte g-recaptcha-response introuvable |
SPA n'a pas encore rendu le widget | Utilisez wait_for_selector avec un délai d'attente adéquat |
| Jeton injecté mais le formulaire n'est pas soumis | Rappel non déclenché | Recherchez et appelez la fonction data-callback |
| La clé du site ne figure pas dans la source de la page | Regroupé en JS ou chargé dynamiquement | Attendez le rendu du widget, puis extrayez-le de l'iframe src |
| Le jeton fonctionne une fois puis échoue | SPA restitue le composant, jeton d'effacement | Injecter le jeton immédiatement avant la soumission du formulaire |
| Le widget est restitué après l'injection du jeton | La réactivité de React/Vue efface la valeur | Utilisez l'approche data-callback au lieu de définir une zone de texte |
FAQ
Puis-je ignorer le navigateur et résoudre les SPA reCAPTCHA avec uniquement des requêtes HTTP ?
Si vous pouvez extraire la clé du site et répliquer l'appel API de soumission du formulaire, oui. De nombreux formulaires SPA sont soumis via un point de terminaison d'API REST : vous pouvez l'appeler directement avec le jeton. Mais vous avez d'abord besoin d'un navigateur pour découvrir la clé du site et le point de terminaison de l'API.
Comment gérer le reCAPTCHA qui n'apparaît que sur certaines actions de l'utilisateur ?
Automatisez l'action de déclenchement (cliquez sur un bouton, remplissez un formulaire, accédez à un itinéraire), puis attendez que l'élément reCAPTCHA apparaisse. Utilisez wait_for_selector avec un délai d'attente raisonnable.
CaptchaAI se soucie-t-il de savoir si le reCAPTCHA se trouve dans un SPA ?
Non. CaptchaAI n’a besoin que de la clé du site et de l’URL de la page. La façon dont le widget se charge sur la page n'affecte pas la résolution.
Articles connexes
- Comment résoudre le rappel Recaptcha V2 à l'aide de l'API
- Gestion du tourniquet Recaptcha V2 sur le même site
- Mécanisme de rappel Recaptcha V2
Prochaines étapes
Résolvez les reCAPTCHA chargés dynamiquement dans n'importe quel SPA -récupérez votre clé API CaptchaAI.