No necesitas Puppeteer ni Playwright para resolver CAPTCHA. Con Axios y CaptchaAI, puedes resolver reCAPTCHA, Turnstile y CAPTCHA de imágenes usando peticiones HTTP puras, sin overhead de navegador.
Requisitos
| Requisito | Detalles |
|---|---|
| Node.js | 16+ |
| axios | 1.x |
| Clave API CaptchaAI | Consigue uno aquí |
npm install axios
Cliente CaptchaAI
const axios = require("axios");
class CaptchaAI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = "https://ocr.captchaai.com";
}
async submit(params) {
params.key = this.apiKey;
const resp = await axios.get(`${this.baseUrl}/in.php`, { params });
const text = resp.data;
if (!String(text).startsWith("OK|")) {
throw new Error(`Submit failed: ${text}`);
}
return String(text).split("|")[1];
}
async poll(taskId, timeoutMs = 300000) {
const deadline = Date.now() + timeoutMs;
const params = { key: this.apiKey, action: "get", id: taskId };
while (Date.now() < deadline) {
await new Promise((r) => setTimeout(r, 5000));
const resp = await axios.get(`${this.baseUrl}/res.php`, { params });
const text = String(resp.data);
if (text === "CAPCHA_NOT_READY") continue;
if (text.startsWith("OK|")) return text.split("|").slice(1).join("|");
throw new Error(`Solve failed: ${text}`);
}
throw new Error(`Timeout after ${timeoutMs}ms for task ${taskId}`);
}
async solve(params, timeoutMs = 300000) {
const taskId = await this.submit(params);
return this.poll(taskId, timeoutMs);
}
async getBalance() {
const resp = await axios.get(`${this.baseUrl}/res.php`, {
params: { key: this.apiKey, action: "getbalance" },
});
return parseFloat(resp.data);
}
}
module.exports = CaptchaAI;
Resuelva reCAPTCHA v2 (sin navegador)
const CaptchaAI = require("./captchaai");
async function main() {
const solver = new CaptchaAI(process.env.CAPTCHAAI_API_KEY);
// Solve the CAPTCHA without opening any browser
const token = await solver.solve({
method: "userrecaptcha",
googlekey: "6Le-wvkS...",
pageurl: "https://staging.example.com/qa-login",
});
// Submit form with the token using Axios
const resp = await axios.post("https://staging.example.com/qa-login", {
username: "user",
password: "pass",
"g-recaptcha-response": token,
});
console.log(`Login response: ${resp.status}`);
}
main().catch(console.error);
Resolver Turnstile (sin navegador)
const token = await solver.solve({
method: "turnstile",
sitekey: "0x4AAAAA...",
pageurl: "https://example.com",
});
// Submit with Turnstile token
const resp = await axios.post("https://example.com/api/verify", {
"cf-turnstile-response": token,
data: "payload",
});
Resolver CAPTCHA de imágenes
const fs = require("fs");
const imageBuffer = fs.readFileSync("captcha.png");
const imageB64 = imageBuffer.toString("base64");
const text = await solver.solve({
method: "base64",
body: imageB64,
});
console.log(`CAPTCHA text: ${text}`);
// Submit form with solved text
const resp = await axios.post("https://example.com/verify", {
captcha: text,
other_data: "value",
});
Flujo de trabajo de raspado completo
Extraiga una página protegida por CAPTCHA sin ningún navegador:
const CaptchaAI = require("./captchaai");
const axios = require("axios");
const cheerio = require("cheerio");
async function scrapeProtectedPage(url) {
const solver = new CaptchaAI(process.env.CAPTCHAAI_API_KEY);
// Step 1: Fetch the page
const page = await axios.get(url);
const $ = cheerio.load(page.data);
// Step 2: Extract the reCAPTCHA site key
const siteKey = $(".g-recaptcha").attr("data-sitekey");
if (!siteKey) {
console.log("No CAPTCHA found, returning page content");
return page.data;
}
// Step 3: Solve the CAPTCHA
console.log(`Solving CAPTCHA for ${url}...`);
const token = await solver.solve({
method: "userrecaptcha",
googlekey: siteKey,
pageurl: url,
});
// Step 4: Submit form with token
const formAction = $("form").attr("action") || url;
const formData = {};
$("form input").each((_, el) => {
const name = $(el).attr("name");
const value = $(el).attr("value") || "";
if (name) formData[name] = value;
});
formData["g-recaptcha-response"] = token;
const result = await axios.post(formAction, new URLSearchParams(formData), {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
return result.data;
}
scrapeProtectedPage("https://example.com/data")
.then((data) => console.log("Success:", typeof data))
.catch(console.error);
Resolución concurrente
async function solveBatch(urls, siteKey) {
const solver = new CaptchaAI(process.env.CAPTCHAAI_API_KEY);
const promises = urls.map(async (url) => {
try {
const token = await solver.solve({
method: "userrecaptcha",
googlekey: siteKey,
pageurl: url,
});
return { url, token, error: null };
} catch (error) {
return { url, token: null, error: error.message };
}
});
const results = await Promise.all(promises);
const solved = results.filter((r) => r.token);
console.log(`Solved ${solved.length}/${urls.length}`);
return results;
}
Solución de problemas
| Error | Causa | Solución |
|---|---|---|
AxiosError: getaddrinfo ENOTFOUND |
Problema de DNS | Verificar la conectividad de la red |
Submit failed: ERROR_WRONG_USER_KEY |
Clave API incorrecta | Verificar clave desde el panel |
Submit failed: ERROR_ZERO_BALANCE |
Sin fondos | Agregar saldo a la cuenta |
| Token rechazado por el sitio de destino | Token caducado | Enviar token dentro de 60 segundos |
Preguntas frecuentes
¿Por qué evitar los navegadores para resolver CAPTCHA?
Los navegadores consumen entre 200 y 500 MB de RAM por instancia. HTTP puro con CaptchaAI utiliza ~5 MB. Esto es entre 40 y 100 veces más eficiente para la automatización del lado del servidor.
¿Cuándo necesito todavía un navegador?
Cuando el sitio requiere renderizado de JavaScript para el contenido. Específicamente para los CAPTCHA, nunca necesitas un navegador: CaptchaAI maneja la resolución de forma remota.
¿Puedo usar fetch en lugar de Axios?
Sí. Node.js 18+ incluye fetch nativo. Los parámetros de la API CaptchaAI son los mismos.
Guías relacionadas
- Tutorial de scraping CAPTCHA con Node.js
- Integración HTTPX + CaptchaAI
- Curl + CaptchaAI CLI