Resolver un reCAPTCHA v2 dentro de un scraper se reduce a un intercambio de tres pasos con una API de resolución como CaptchaAI:
- Extraes el
sitekeyque el sitio incrusta en el HTML de la página. - Se lo envías a la API junto con la URL de la página y esperas a que te devuelva un token válido.
- Vuelves a inyectar ese token en la página para que el backend del sitio deje pasar la solicitud.
Mientras ese token siga siendo válido, tu extracción continúa sin que ningún humano tenga que marcar la casilla. Esta guía recorre el flujo completo con código listo para usar en Python (Selenium) y Node.js (Puppeteer), más una ruta solo HTTP sin navegador.
Qué necesita tu scraper para resolver reCAPTCHA v2
Todo widget de reCAPTCHA v2 expone dos datos que tu scraper tiene que capturar antes de delegar la resolución:
| Parámetro | Qué es |
|---|---|
googlekey |
El sitekey público incrustado en el HTML de la página |
pageurl |
La URL donde aparece el CAPTCHA |
Tu scraper envía ambos a la API de CaptchaAI, espera a que se complete la resolución y recibe un token. Ese token se inyecta en el campo g-recaptcha-response de la página (o se pasa a la función callback), y el backend del sitio de destino lo verifica contra Google antes de permitir que la solicitud siga adelante.
Resolver reCAPTCHA v2 con Selenium en Python
import requests
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
# Step 1: Open the page with Selenium
driver = webdriver.Chrome()
driver.get("https://example.com/protected-page")
# Step 2: Extract the sitekey
sitekey = driver.find_element(By.CSS_SELECTOR, ".g-recaptcha").get_attribute("data-sitekey")
page_url = driver.current_url
# Step 3: Submit to CaptchaAI
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1
}).json()
task_id = response["request"]
# Step 4: Poll for result
token = None
for _ in range(40):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": task_id,
"json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
break
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve failed: {result['request']}")
# Step 5: Inject the token and submit
driver.execute_script(
f'document.getElementById("g-recaptcha-response").innerHTML = "{token}";'
)
# Check for callback
callback = driver.execute_script(
'var el = document.querySelector(".g-recaptcha"); '
'return el ? el.getAttribute("data-callback") : null;'
)
if callback:
driver.execute_script(f'{callback}("{token}");')
else:
driver.find_element(By.CSS_SELECTOR, "form").submit()
# Step 6: Scrape the data
print(driver.page_source[:500])
driver.quit()
Resolver reCAPTCHA v2 con Puppeteer en Node.js
const puppeteer = require("puppeteer");
async function scrapeWithCaptcha(url) {
const browser = await puppeteer.launch({ headless: "new" });
const page = await browser.newPage();
await page.goto(url, { waitUntil: "networkidle2" });
// Extract sitekey
const sitekey = await page.$eval(".g-recaptcha", (el) => el.dataset.sitekey);
// Submit to CaptchaAI
const submitRes = await fetch(
`https://ocr.captchaai.com/in.php?${new URLSearchParams({
key: "YOUR_API_KEY",
method: "userrecaptcha",
googlekey: sitekey,
pageurl: url,
json: 1,
})}`
);
const { request: taskId } = await submitRes.json();
// Poll for result
let token;
for (let i = 0; i < 40; i++) {
await new Promise((r) => setTimeout(r, 5000));
const res = await fetch(
`https://ocr.captchaai.com/res.php?${new URLSearchParams({
key: "YOUR_API_KEY",
action: "get",
id: taskId,
json: 1,
})}`
);
const data = await res.json();
if (data.status === 1) {
token = data.request;
break;
}
if (data.request !== "CAPCHA_NOT_READY")
throw new Error(`Solve failed: ${data.request}`);
}
// Inject token
await page.evaluate((t) => {
document.getElementById("g-recaptcha-response").innerHTML = t;
const cb = document.querySelector(".g-recaptcha")?.dataset.callback;
if (cb && window[cb]) window[cb](t);
}, token);
// Wait for navigation after form submit
await page.waitForNavigation({ waitUntil: "networkidle2" });
const content = await page.content();
await browser.close();
return content;
}
scrapeWithCaptcha("https://example.com/protected-page").then(console.log);
¿Navegador o solo HTTP? Elige la ruta según el sitio
No todos los flujos necesitan un navegador completo. Antes de escribir código, decide la ruta según cómo valide el token el sitio de destino:
| Situación | Ruta recomendada |
|---|---|
| El sitio valida el token con un callback de JavaScript | Navegador (Selenium o Puppeteer) |
El sitio acepta g-recaptcha-response como campo POST |
Solo HTTP, sin navegador |
| El sitio bloquea navegadores headless antes de mostrar el CAPTCHA | Navegador con configuración estándar |
Resolver reCAPTCHA v2 sin navegador (solo HTTP)
Si el sitio de destino entrega el CAPTCHA dentro de un envío de formulario, puedes saltarte el navegador por completo y trabajar solo con solicitudes HTTP. Es más rápido y consume muchos menos recursos:
import requests
import time
session = requests.Session()
session.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"
# Load the page to get cookies
session.get("https://example.com/protected-page")
# Solve the CAPTCHA
sitekey = "6Le-wvkSAAAAAN..." # extracted from page HTML
solve_resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": "YOUR_API_KEY", "method": "userrecaptcha",
"googlekey": sitekey, "pageurl": "https://example.com/protected-page",
"json": 1
}).json()
task_id = solve_resp["request"]
time.sleep(15)
# Poll
for _ in range(30):
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY", "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
break
time.sleep(5)
# Submit with token
resp = session.post("https://example.com/protected-page", data={
"g-recaptcha-response": token,
"other_field": "value"
})
print(resp.text[:500])
Cuándo tu navegador headless queda bloqueado
Algunos sitios detectan navegadores headless y los bloquean antes incluso de mostrar el CAPTCHA. Si te frenan antes de ver el reCAPTCHA, prueba estos ajustes:
- Usa el modo
headless: "new"de Puppeteer, más cercano al comportamiento de un navegador real - Define un User-Agent real en lugar del predeterminado de automatización
- Mantén una configuración estándar del navegador: idioma, viewport y cabeceras coherentes
- Enruta las solicitudes de extracción posteriores a través de una salida de red autorizada
Un escenario habitual: monitoreo de portales y marketplaces
Piensa en un equipo que hace seguimiento de precios en un marketplace regional (MercadoLibre, Amazon.es) o que valida un portal de trámites públicos —una cita previa, el SAT, AFIP— donde un reCAPTCHA v2 corta la navegación automatizada. El patrón es siempre el mismo: detectas el widget, delegas la resolución en la API y reanudas la extracción con el token inyectado.
Para que ese trabajo sea sostenible, respeta los términos de servicio y la normativa de protección de datos aplicable (RGPD y LOPDGDD en España, LFPDPPP en México, entre otras): extrae solo datos públicos y automatiza únicamente flujos que tengas autorización para consultar. Y trata el coste como un gasto mensual predecible en USD, porque CaptchaAI factura por thread concurrente y no por resolución:
| Plan | Precio | Threads | Ideal para |
|---|---|---|---|
| BASIC | $15/mes | 5 threads | Volúmenes bajos y pruebas iniciales |
| ADVANCE | $90/mes | 50 threads | Extracción de gran volumen en paralelo |
Para agencias y freelancers que facturan en monedas locales volátiles, un coste fijo en USD es más fácil de presupuestar que el pago por cada CAPTCHA resuelto.
Preguntas frecuentes
¿Sirve este flujo para reCAPTCHA v2 invisible?
Sí. El reCAPTCHA v2 invisible usa el mismo sitekey y devuelve un g-recaptcha-response; envías los mismos parámetros a la API y, en vez de marcar una casilla, disparas el callback de la página con el token. El código de esta guía ya cubre ese caso.
¿Qué plan de CaptchaAI conviene para scraping de gran volumen?
Depende de cuántas resoluciones necesites en paralelo. Como CaptchaAI factura por thread concurrente con resoluciones ilimitadas, esta es la referencia rápida:
- BASIC ($15/mes, 5 threads) para volúmenes bajos o pruebas iniciales
- ADVANCE ($90/mes, 50 threads) cuando lanzas muchas extracciones a la vez
No hay tarifa por CAPTCHA resuelto, así que subes de threads solo cuando tu concurrencia lo pide.
¿Necesito ejecutar un navegador para cada resolución?
No siempre. Si el sitio acepta g-recaptcha-response como campo POST, la ruta solo HTTP evita el navegador y es mucho más ligera. Si la validación depende de un callback de JavaScript, necesitas un navegador como Selenium o Puppeteer.
¿Es legal hacer scraping de sitios protegidos con reCAPTCHA?
Depende del sitio y de tu jurisdicción. Resolver el CAPTCHA es una operación técnica; la responsabilidad legal está en qué datos extraes y con qué permiso. Ten presentes estos límites:
- Limítate a datos públicos y respeta los términos de servicio del sitio
- Cumple la normativa de protección de datos aplicable a tu operación
- No automatices flujos autenticados que no te pertenezcan
¿Y si el sitio usa reCAPTCHA Enterprise?
Añade enterprise=1 a tu solicitud a CaptchaAI y el resto del flujo no cambia. Tienes el detalle en cómo resolver reCAPTCHA v2 Enterprise con la API.
Empieza a resolver reCAPTCHA v2 en tu pipeline
- Consigue tu API key en captchaai.com/api.php
- Extrae el
sitekeyde la página objetivo - Usa los ejemplos de arriba para resolver e inyectar el token
- Escala con resoluciones simultáneas (más threads) para flujos de gran volumen