Cuando la resolución de Grid Image CAPTCHA falla, la causa casi siempre cae en uno de tres puntos: cómo codificas la imagen, cómo la capturas del navegador o cómo interpretas los índices que devuelve la API. Esta guía recorre cada error por su código y te da el arreglo concreto para volver a resolver a la primera. Es un fallo habitual al automatizar el QA de portales protegidos, donde el grid suele vivir dentro de un iframe.
Diagnóstico rápido
Recorre esta tabla antes de entrar al detalle: el fallo suele estar en una de estas ocho filas.
| Revisa | Acción |
|---|---|
| ¿Formato de imagen? | PNG o JPEG, bien codificados |
| ¿Tamaño de imagen? | Menos de 600 KB |
| ¿Cuadrícula completa? | Incluye toda la cuadrícula con márgenes |
| ¿Calidad de imagen? | Nítida, sin desenfoque ni reducción |
| ¿Formato de la solución? | Analiza bien los índices separados por comas |
| ¿Base del índice? | Convierte de base 1 a base 0 para los arrays |
| ¿Contexto del iframe? | Cambia al iframe del CAPTCHA si existe |
| ¿El CAPTCHA caducó? | Envía la imagen justo después de capturarla |
Errores al enviar la imagen
ERROR_WRONG_FILE_EXTENSION
Causa: el archivo que envías no llega como un formato de imagen válido, casi siempre por el prefijo de data URI o una base64 mal codificada. Corrígelo en este orden:
- Usa únicamente PNG o JPEG.
- Comprueba que la cadena base64 esté bien codificada.
- Elimina el prefijo
data:image/...;base64,antes de enviar.
# WRONG — includes data URI prefix
body = "data:image/png;base64,iVBORw0KGgo..."
# CORRECT — raw base64 only
body = "iVBORw0KGgo..."
ERROR_TOO_BIG_CAPTCHA_FILESIZE
Causa: la imagen supera el tamaño máximo de archivo, normalmente 600 KB. Reescálala antes de codificarla en base64.
from PIL import Image
import io
import base64
# Resize if too large
img = Image.open("captcha.png")
if img.width > 600:
ratio = 600 / img.width
img = img.resize((600, int(img.height * ratio)), Image.LANCZOS)
buffer = io.BytesIO()
img.save(buffer, format="PNG")
b64 = base64.b64encode(buffer.getvalue()).decode()
ERROR_ZERO_CAPTCHA_FILESIZE
Causa: el archivo llega vacío o la extracción falló, casi siempre por leer el elemento antes de que termine de cargar. Verifica tres cosas:
- Que la imagen se cargó antes de extraerla.
- Que el atributo
srcno esté vacío. - Que esperas a las imágenes con carga diferida (lazy loading).
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Wait for image to load
WebDriverWait(driver, 10).until(
lambda d: d.find_element(By.CSS_SELECTOR, ".captcha img").get_attribute("complete") == "true"
)
Cuando la imagen se envía pero no se resuelve
ERROR_CAPTCHA_UNSOLVABLE
Causa: la imagen está demasiado borrosa o distorsionada, o los objetos son irreconocibles. Captúrala a resolución completa, sin reducir su tamaño, y sin superposiciones ni marcas de agua sobre la cuadrícula. Si el desafío es ambiguo de origen, reintenta con un CAPTCHA nuevo.
El solver marca las celdas equivocadas
Causa: calidad de imagen baja o captura parcial. Captura el elemento CAPTCHA completo, bordes incluidos, con unos píxeles de margen, y guarda la imagen para revisarla tú mismo antes de darla por buena.
# Take a proper element screenshot
captcha_el = driver.find_element(By.CSS_SELECTOR, "#captcha-container")
captcha_el.screenshot("debug_captcha.png")
# Open and check manually
from PIL import Image
Image.open("debug_captcha.png").show()
Errores al aplicar la solución en el DOM
Desfase de índice (off-by-one)
Causa: la respuesta de la API empieza en 1 y la indexación de arrays en 0. Si marcas las celdas sin restar 1 a cada índice, siempre quedarás desplazado una posición.
# API returns "1,3,5" (1-based)
solution = "1,3,5"
indices = [int(i) for i in solution.split(",")]
# DON'T: use directly as array index
# cells[1], cells[3], cells[5] ← WRONG (off by one)
# DO: convert to 0-based
for idx in indices:
cells[idx - 1].click() # 1→0, 3→2, 5→4
Las celdas no responden al clic
Causa: el destino del clic es incorrecto: una superposición, un iframe o un shadow DOM. Cambia al iframe correcto antes de buscar celdas.
# Check if captcha is in an iframe
iframes = driver.find_elements(By.TAG_NAME, "iframe")
for iframe in iframes:
if "captcha" in iframe.get_attribute("src").lower():
driver.switch_to.frame(iframe)
break
# Now find and click cells
cells = driver.find_elements(By.CSS_SELECTOR, ".grid-cell")
Cuadrícula dinámica: los mosaicos cambian tras cada clic
Causa: las cuadrículas dinámicas al estilo reCAPTCHA reemplazan los mosaicos a medida que los marcas. Para reCAPTCHA, usa el método por token en vez del de imagen; gestiona esa rotación de forma automática.
# Token method handles dynamic grids automatically
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": "SITE_KEY",
"pageurl": "https://example.com",
"json": 1
})
El CAPTCHA caduca antes de recibir la solución
Causa: los CAPTCHA de cuadrícula suelen caducar en 2 o 3 minutos, así que cualquier demora en la captura o el sondeo se paga cara. Bajo carga —al monitorear un portal de trámites regional— la ventana se cierra fácil. Envía la imagen justo tras capturarla y, si la resolución tarda más de 60 segundos, actualiza y reintenta.
CAPCHA_NOT_READY se repite sin fin
Causa: puede que la tarea haya fallado en silencio y el sondeo nunca reciba respuesta. Fija un máximo de reintentos y corta el bucle ante cualquier error real.
for attempt in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") not in ["CAPCHA_NOT_READY"]:
break # Actual error, stop polling
raise Exception("Grid captcha solve failed — refresh and retry")
Preguntas frecuentes
¿Conviene más PNG o JPEG?
PNG da los mejores resultados porque no tiene pérdidas y conserva los bordes de las celdas. JPEG funciona, pero una compresión agresiva difumina esos límites.
¿Cómo corrijo el desfase de índice al marcar las celdas?
La API devuelve posiciones que empiezan en 1 y los arrays en 0: resta 1 a cada índice antes de usarlo (cells[idx - 1]) o quedarás desplazado una posición.
¿Grid Image CAPTCHA se cobra por resolución o va incluido en mi plan?
Va incluido. CaptchaAI factura por thread concurrente, no por CAPTCHA resuelto: cada plan trae resoluciones ilimitadas por thread. Con BASIC ($15/mes, 5 threads) resuelves varios grids en paralelo.
¿Qué hago si la cuadrícula tiene dimensiones no estándar?
Nada especial. CaptchaAI analiza la imagen tal cual y las cuadrículas fuera de lo habitual (5×3, 2×4) se resuelven por análisis visual, sin asumir un tamaño fijo.
Guías relacionadas
- Cómo resolver Grid Image CAPTCHA automáticamente
- Referencia de códigos de error de CaptchaAI