Sí, los CAPTCHA de un portal de registros públicos se resuelven por API, y casi siempre con el método más antiguo del catálogo: descargas la imagen dentro de la misma sesión que cargó el formulario, la envías en base64 al endpoint in.php, recuperas el texto en res.php y lo devuelves antes de que caduque el token oculto. El reconocimiento es la parte fácil; la sesión es donde se rompe casi todo.
Aquí no negocias con un anti-bot moderno como Cloudflare Turnstile, sino con software heredado de juzgados, catastros y registros mercantiles. Abajo tienes qué CAPTCHA usa cada categoría de portal, qué parámetros suben la tasa de acierto, código en Python y Node.js listo para copiar y un diagnóstico para cuando la búsqueda vuelve vacía.
Qué CAPTCHA usa cada tipo de portal
| Categoría del portal | CAPTCHA habitual | Cómo se ve el desafío |
|---|---|---|
| Consulta de expedientes judiciales | CAPTCHA de texto a medida | Cadena alfanumérica de 5–6 caracteres deformada |
| Registro de la propiedad | CAPTCHA matemático | "¿Cuánto es 4 + 7?" |
| Registro mercantil y de sociedades | Texto sobre imagen | Letras onduladas con ruido de línea |
| Registro civil | reCAPTCHA v2 | Selección en cuadrícula de imágenes |
| Licencias de obra | CAPTCHA de texto simple | Código numérico de 4 dígitos |
| Garantías mobiliarias | OCR a medida | Mayúsculas y minúsculas mezcladas sobre fondo con ruido |
Casi todas usan el mismo método de la API: imagen/OCR, con más de 27.500 variantes reconocidas y tiempos por debajo de 0,5 s. Si el portal ya migró, reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile y GeeTest v3 también están cubiertos. hCaptcha y FunCaptcha no son compatibles por ahora, y GeeTest v4 figura como próximamente.
Parámetros de la API que suben la tasa de acierto
Estos CAPTCHA son predecibles: normalmente sabes si el código es numérico, cuántos caracteres tiene o si es una operación aritmética. Pasar ese dato en la tarea es la mejora más barata posible.
| Parámetro | Valor | Cuándo usarlo |
|---|---|---|
method |
base64 |
Ya descargaste la imagen como bytes |
method |
post |
Envías el archivo de imagen directamente |
language |
0 |
CAPTCHA de texto con alfabeto latino |
numeric |
1 |
El código es solo de dígitos |
min_len / max_len |
Varía | La longitud del código es predecible |
textinstructions |
Instrucción libre | Operaciones matemáticas o formatos poco habituales |
min_len y max_len descartan respuestas imposibles antes de enviar el formulario: en portales que bloquean tras varios fallos, eso vale más que unos milisegundos de latencia.
Consulta de expedientes judiciales en Python
El patrón es siempre el mismo: cargar la página con una Session persistente, localizar la etiqueta img, descargarla con esa misma sesión y enviar el texto resuelto con el resto del formulario.
import requests
import base64
import time
from urllib.parse import urljoin
class PublicRecordsSearcher:
def __init__(self, api_key):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def search_court_records(self, portal_url, case_number):
"""Search court records, solving image CAPTCHAs as needed."""
# Load the search page
page = self.session.get(f"{portal_url}/search")
# Extract CAPTCHA image
captcha_img_url = self._extract_captcha_url(page.text, portal_url)
if not captcha_img_url:
# No CAPTCHA on this page
return self._submit_search(portal_url, case_number)
# Download and solve CAPTCHA
img_response = self.session.get(captcha_img_url)
captcha_text = self._solve_image_captcha(img_response.content)
# Submit search with solved CAPTCHA
return self._submit_search(portal_url, case_number, captcha_text)
def _extract_captcha_url(self, html, base_url):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
# Look for common CAPTCHA image patterns
captcha_img = (
soup.find("img", {"id": "captchaImage"}) or
soup.find("img", {"class": "captcha"}) or
soup.find("img", attrs={"src": lambda s: s and "captcha" in s.lower()})
)
if captcha_img and captcha_img.get("src"):
return urljoin(base_url, captcha_img["src"])
return None
def _solve_image_captcha(self, image_bytes):
img_base64 = base64.b64encode(image_bytes).decode("utf-8")
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "base64",
"body": img_base64,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(30):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("CAPTCHA solve timed out")
def _submit_search(self, portal_url, case_number, captcha_text=None):
form_data = {"caseNumber": case_number}
if captcha_text:
form_data["captcha"] = captcha_text
response = self.session.post(
f"{portal_url}/search/results",
data=form_data
)
return response.text
# Usage
searcher = PublicRecordsSearcher("YOUR_API_KEY")
results = searcher.search_court_records(
"https://courts.example.gov",
"2024-CV-12345"
)
Fíjate en que la imagen se descarga con self.session.get() y no con un requests.get() suelto: la cookie que emitió la página de búsqueda es la que valida el CAPTCHA.
CAPTCHA matemáticos, el patrón más común en registros de propiedad
Los catastros suelen usar sumas o restas renderizadas como imagen. No hace falta un método especial: se tratan como reconocimiento de texto y se guía la respuesta con textinstructions para que devuelva el resultado, no la operación.
def solve_math_captcha(self, image_bytes):
"""Solve math CAPTCHAs like '4 + 7 = ?'"""
img_base64 = base64.b64encode(image_bytes).decode("utf-8")
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "base64",
"body": img_base64,
"textinstructions": "solve the math equation and return only the number",
"json": 1
})
task_id = resp.json()["request"]
# Poll for result
for _ in range(30):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("Math CAPTCHA solve timed out")
Recorrer varios portales desde Node.js
Cuando consultas varios registros a la vez, aísla cada portal en su propio try y devuelve el error como dato en lugar de abortar el lote: un juzgado caído no debería tumbar la búsqueda en el registro mercantil.
class RecordsAggregator {
constructor(apiKey) {
this.apiKey = apiKey;
}
async searchAcrossPortals(query, portals) {
const results = [];
for (const portal of portals) {
try {
const data = await this.searchPortal(portal, query);
results.push({ portal: portal.name, records: data });
} catch (error) {
results.push({ portal: portal.name, error: error.message });
}
}
return results;
}
async searchPortal(portal, query) {
const pageResponse = await fetch(portal.searchUrl);
const html = await pageResponse.text();
// Check for image CAPTCHA
const captchaMatch = html.match(/captcha[^"]*\.(?:png|jpg|gif)/i);
let captchaAnswer = null;
if (captchaMatch) {
const imgUrl = new URL(captchaMatch[0], portal.searchUrl).href;
const imgData = await fetch(imgUrl);
const buffer = await imgData.arrayBuffer();
const base64 = Buffer.from(buffer).toString('base64');
captchaAnswer = await this.solveImageCaptcha(base64);
}
// Submit search
const formData = new URLSearchParams({ q: query });
if (captchaAnswer) formData.append('captcha', captchaAnswer);
const response = await fetch(portal.searchUrl, {
method: 'POST',
body: formData
});
return response.text();
}
async solveImageCaptcha(base64Image) {
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: new URLSearchParams({
key: this.apiKey,
method: 'base64',
body: base64Image,
json: '1'
})
});
const { request: taskId } = await submitResp.json();
for (let i = 0; i < 30; i++) {
await new Promise(r => setTimeout(r, 3000));
const result = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const data = await result.json();
if (data.status === 1) return data.request;
}
throw new Error('CAPTCHA solve timed out');
}
}
// Usage
const aggregator = new RecordsAggregator('YOUR_API_KEY');
const results = await aggregator.searchAcrossPortals('Smith LLC', [
{ name: 'State Business Registry', searchUrl: 'https://sos.example.gov/search' },
{ name: 'County Court Records', searchUrl: 'https://courts.example.gov/search' }
]);
Escenario: verificar un proveedor en tres registros distintos
Una consultora en Ciudad de México verifica a un proveedor antes de firmar: la matriz en el registro mercantil español, un expediente judicial estatal en México y una inscripción provincial en Argentina. Tres portales, tres CAPTCHA distintos, unas 120 consultas al día en temporada alta.
Ese volumen cabe de sobra en el plan BASIC ($15/mes, 5 threads). Si el equipo pasa a un barrido nocturno de miles de expedientes, STANDARD ($30/mes, 15 threads) o ADVANCE ($90/mes, 50 threads) amplían la concurrencia sin tocar el código: se factura por thread simultáneo, con resoluciones ilimitadas dentro del plan, así que el coste mensual en USD es previsible aunque el volumen diario baile.
Una nota que no es opcional: consulta solo información de acceso público y respeta los términos de cada portal y la normativa de protección de datos aplicable (RGPD y LOPDGDD en España, LFPDPPP en México) antes de almacenar o cruzar los datos.
Cuando la búsqueda vuelve vacía: diagnóstico
| Síntoma | Causa habitual | Qué hacer |
|---|---|---|
| La imagen del CAPTCHA devuelve 403 | Falta la cookie de sesión | Carga primero la página de búsqueda y descarga la imagen con la misma sesión |
| El texto resuelto se rechaza | Imagen de muy baja calidad | Preprocesa la imagen y acota la longitud con min_len / max_len |
| El CAPTCHA se regenera al enviar | El token oculto del formulario caducó | Extrae los campos ocultos en la misma petición que la imagen |
| La búsqueda responde sin resultados | Se perdieron las cookies en la redirección | Usa allow_redirects=True y reutiliza la sesión en todo el flujo |
Si la culpa es de la imagen, subir el contraste y limpiar el ruido cambia el resultado: la guía de preprocesamiento de imágenes detalla las técnicas.
Preguntas frecuentes
¿Cuántos threads necesito para consultar varios portales en paralelo?
Un thread es un CAPTCHA en curso, no un portal. Con tres portales y una consulta simultánea en cada uno sobran los 5 threads de BASIC ($15/mes); a dos consultas por portal ya necesitas 6 y toca STANDARD ($30/mes, 15 threads). Para barridos masivos, ADVANCE ($90/mes, 50 threads).
¿Qué hago si el portal cambia el CAPTCHA cada vez que envío el formulario?
Casi siempre es el token oculto del formulario, no el CAPTCHA. Extrae los campos hidden en la misma petición en la que descargas la imagen y envíalo todo junto; si tardas más de un par de minutos, recarga la página.
¿CaptchaAI resuelve el reCAPTCHA v2 de los registros civiles?
Sí. reCAPTCHA v2 (incluidas la invisible y Enterprise), reCAPTCHA v3, Cloudflare Turnstile y GeeTest v3 se resuelven con la misma clave API. hCaptcha y FunCaptcha no son compatibles por ahora.
¿Puedo automatizar consultas en portales públicos sin problemas legales?
Depende del portal: cada sede electrónica tiene sus propias condiciones de uso y límites de frecuencia. Consulta solo datos abiertos, mantén una frecuencia razonable y revisa la normativa de protección de datos antes de almacenar resultados.
Próximos pasos
Obtén tu clave API de CaptchaAI y resuelve los CAPTCHA de imagen de los portales gubernamentales desde tu propio código.