Solución de Problemas

Respuestas incorrectas en CAPTCHA de imagen: optimiza la calidad

Cuando el motor OCR de CaptchaAI te devuelve un texto que no coincide con lo que ves en pantalla, la culpa casi nunca es del modelo de resolución: es lo que le estás enviando. Un CAPTCHA de imagen se resuelve leyendo píxeles, así que si esos píxeles llegan recortados, comprimidos o mal codificados, la respuesta saldrá torcida por muchas veces que reintentes. Casi todos se diagnostican en minutos desde tu propio código: revisa primero la calidad y el recorte, luego la codificación y, al final, las pistas de tipo que pasas a la API.


Por qué un CAPTCHA de imagen devuelve una respuesta incorrecta

Antes de tocar nada, ubica el síntoma en una de estas causas. Cada fila apunta a una corrección distinta, y confundirlas hace perder tiempo.

Causa Frecuencia Cómo corregirlo
Imagen recortada de más o de menos Muy frecuente Captura el elemento CAPTCHA completo
Baja resolución o exceso de compresión Frecuente Envía una imagen de mayor calidad
Codificación de la imagen incorrecta Frecuente Revisa la codificación base64
Falta la pista de idioma o de tipo Ocasional Añade language o textinstructions
Imagen caducada o rotada Ocasional Captura una imagen nueva justo antes de resolver

Con imágenes bien enviadas, CaptchaAI cubre más de 27.500 variantes de CAPTCHA de imagen con alta precisión; cuando algo falla, el punto débil suele estar en tu pipeline, no en el solver.


Comprueba la calidad de la imagen antes de enviarla

La comprobación más rentable es la más barata: validar la imagen en local antes de que consuma una llamada a la API. Este control revisa tres cosas que rompen el OCR: dimensiones por debajo del mínimo útil (unos 50x20 px), una imagen casi en blanco (recorte fallido o elemento sin cargar) y un peso fuera de rango. Mantén el archivo por debajo de 600 KB; más allá suele indicar que envías la página entera.

import base64
from io import BytesIO
from PIL import Image


def validate_captcha_image(image_path):
    """Check image quality before submitting to CaptchaAI."""
    img = Image.open(image_path)
    width, height = img.size
    issues = []

    # Minimum resolution
    if width < 50 or height < 20:
        issues.append(f"Too small: {width}x{height}px (min 50x20)")

    # Check if mostly blank
    pixels = list(img.getdata())
    if img.mode == "RGB":
        white_count = sum(1 for p in pixels if p[0] > 250 and p[1] > 250 and p[2] > 250)
    else:
        white_count = sum(1 for p in pixels if p > 250)

    blank_ratio = white_count / len(pixels)
    if blank_ratio > 0.95:
        issues.append(f"Image appears blank ({blank_ratio:.0%} white)")

    # File size check
    img_bytes = BytesIO()
    img.save(img_bytes, format="PNG")
    size_kb = img_bytes.tell() / 1024
    if size_kb < 1:
        issues.append(f"File too small ({size_kb:.1f} KB) — may be empty")
    if size_kb > 600:
        issues.append(f"File too large ({size_kb:.0f} KB) — submit under 600 KB")

    return issues


issues = validate_captcha_image("captcha.png")
if issues:
    for issue in issues:
        print(f"WARNING: {issue}")
else:
    print("Image quality OK")

Codifica en Base64 sin corromper la imagen

Si la respuesta llega como un galimatías sin relación con la imagen, sospecha de la codificación. El error clásico es codificar el nombre del archivo (b"captcha.png") en lugar de los bytes que contiene: la API recibe basura y devuelve basura. Lee el archivo en binario, codifícalo y verifica el ida y vuelta con un assert.

import base64


def encode_captcha(image_path):
    """Properly encode a CAPTCHA image to base64."""
    with open(image_path, "rb") as f:
        raw = f.read()

    encoded = base64.b64encode(raw).decode("ascii")

    # Verify round-trip
    decoded = base64.b64decode(encoded)
    assert decoded == raw, "Base64 encoding corrupted the image"

    return encoded


# WRONG — encoding a file path string
bad = base64.b64encode(b"captcha.png").decode()  # Encodes filename, not image!

# CORRECT — encoding file contents
with open("captcha.png", "rb") as f:
    good = base64.b64encode(f.read()).decode()

Mejora la lectura OCR con preprocesamiento

Cuando la respuesta se acerca pero no acierta (un carácter cambiado, una l por una 1), suele deberse a una imagen pequeña o de bajo contraste. Ampliar las imágenes muy chicas hasta unos 200 px de ancho, subir el contraste y aplicar un enfoque ligero le da al OCR más señal. No te pases: sobreprocesar introduce artefactos; resérvalo para los casos difíciles.

from PIL import Image, ImageFilter, ImageEnhance
from io import BytesIO
import base64


def preprocess_captcha(image_path):
    """Improve image quality for better OCR accuracy."""
    img = Image.open(image_path)

    # Convert to RGB if needed
    if img.mode != "RGB":
        img = img.convert("RGB")

    # Upscale small images
    width, height = img.size
    if width < 200:
        scale = 200 / width
        img = img.resize(
            (int(width * scale), int(height * scale)),
            Image.LANCZOS,
        )

    # Increase contrast
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(1.5)

    # Sharpen
    img = img.filter(ImageFilter.SHARPEN)

    # Convert to PNG bytes
    buffer = BytesIO()
    img.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode()

Añade pistas de tipo, longitud e idioma

Muchos fallos "casi correctos" desaparecen cuando le dices a la API qué esperar. Si el CAPTCHA es solo de dígitos, pasa numeric=1; si tiene entre 4 y 6 caracteres, acota con min_len y max_len para que no invente longitudes. Con textinstructions marcas detalles como la sensibilidad a mayúsculas, y con language indicas el alfabeto.

import requests


def solve_image(api_key, image_base64, **hints):
    """Submit image CAPTCHA with quality hints."""
    data = {
        "key": api_key,
        "method": "base64",
        "body": image_base64,
        "json": 1,
    }

    # Add optional hints for better accuracy
    if "language" in hints:
        data["language"] = hints["language"]  # 0=default, 1=Cyrillic, 2=Latin
    if "textinstructions" in hints:
        data["textinstructions"] = hints["textinstructions"]
    if "numeric" in hints:
        data["numeric"] = hints["numeric"]  # 1=digits only, 2=letters only
    if "min_len" in hints:
        data["min_len"] = hints["min_len"]
    if "max_len" in hints:
        data["max_len"] = hints["max_len"]

    resp = requests.post("https://ocr.captchaai.com/in.php", data=data, timeout=30)
    return resp.json()


# Example: Digits-only CAPTCHA, 4-6 characters
result = solve_image(
    "YOUR_API_KEY",
    encoded_image,
    numeric=1,
    min_len=4,
    max_len=6,
)

# Example: Case-sensitive text
result = solve_image(
    "YOUR_API_KEY",
    encoded_image,
    textinstructions="Case-sensitive, enter exactly as shown",
)

Captura solo el elemento del CAPTCHA, no la página

Un recorte descuidado es la causa número uno de respuestas incorrectas. Si capturas toda la página y recortas por coordenadas fijas, cualquier cambio de layout deja el texto medio cortado. Mejor captura el propio elemento con Selenium: obtienes exactamente los píxeles del CAPTCHA, sin bordes ni relleno, y verificas que era visible comprobando el tamaño del PNG.

from selenium import webdriver
from selenium.webdriver.common.by import By
import base64


def capture_captcha_element(driver, selector):
    """Screenshot only the CAPTCHA element, not the full page."""
    element = driver.find_element(By.CSS_SELECTOR, selector)

    # Element screenshot (better than page crop)
    png_bytes = element.screenshot_as_png

    # Verify it's not empty
    if len(png_bytes) < 500:
        raise ValueError("Screenshot too small — element may not be visible")

    return base64.b64encode(png_bytes).decode()


# Usage
driver = webdriver.Chrome()
driver.get("https://example.com")
image_b64 = capture_captcha_element(driver, "img#captchaImage")

Resuelve CAPTCHA dinámicos o rotativos sin que caduquen

Algunos portales rotan la imagen cada pocos segundos. Si capturas, esperas y luego envías, puedes resolver una imagen que ya no está en pantalla, y el sitio rechaza la respuesta aunque el texto fuera correcto. La regla es simple: captura y envía de inmediato. Como los CAPTCHA de imagen se resuelven rápido, un sondeo corto basta.

import time


def solve_with_fresh_image(driver, api_key, captcha_selector):
    """Capture and solve CAPTCHA immediately to avoid expiry."""
    # Wait for CAPTCHA to load fully
    time.sleep(2)

    # Capture fresh
    element = driver.find_element(By.CSS_SELECTOR, captcha_selector)
    png_bytes = element.screenshot_as_png
    body = base64.b64encode(png_bytes).decode()

    # Submit immediately
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "base64",
        "body": body,
        "json": 1,
    }, timeout=30)
    result = resp.json()

    if result.get("status") != 1:
        raise RuntimeError(result.get("request"))

    task_id = result["request"]

    # Poll — image CAPTCHAs solve fast
    time.sleep(5)
    for _ in range(12):
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15)
        data = resp.json()

        if data.get("status") == 1:
            return data["request"]
        if data["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(data["request"])
        time.sleep(3)

    raise TimeoutError("Image solve timeout")

Tabla de diagnóstico rápido

Cuando tengas un fallo concreto delante, usa esta tabla para ir directo a la corrección.

Síntoma Diagnóstico Corrección
La respuesta es un galimatías Codificación base64 incorrecta Verifica la codificación de ida y vuelta
La respuesta se acerca pero falla Baja calidad de imagen Preprocesa: amplía, enfoca, sube contraste
El número de caracteres no cuadra Faltan pistas de longitud Añade min_len / max_len
Mezcla letras y dígitos Falta la pista de tipo Añade numeric=1 o numeric=2
Devuelve una respuesta vacía Imagen en blanco o corrupta Valida la imagen antes de enviarla
Respuesta correcta pero el sitio la rechaza Sensibilidad a mayúsculas Añade textinstructions para el caso

Un caso real: QA de un portal con CAPTCHA de imagen

Un equipo que automatiza pruebas de regresión sobre su propio entorno de staging —un flujo de cita previa que replica el de un portal público en España— veía que una de cada cinco ejecuciones fallaba con un texto casi correcto. No era el solver: el script capturaba la página completa y recortaba por coordenadas, y un banner intermitente desplazaba el CAPTCHA unos píxeles. Al pasar a la captura del elemento y validar el tamaño del PNG antes de enviarlo, los fallos desaparecieron. El coste es predecible en USD (el plan BASIC son $15/mes con 5 threads), algo que encaja con agencias y freelancers que facturan en monedas locales volátiles. Respeta siempre los términos de servicio y la normativa de protección de datos aplicable.


Preguntas frecuentes

¿Por qué CaptchaAI devuelve el texto correcto pero el formulario lo rechaza?

Casi siempre es sensibilidad a mayúsculas y minúsculas, o espacios sobrantes. Añade textinstructions indicando que se distinga el caso y compara carácter por carácter lo que envías con lo que espera el formulario.

¿Cómo distingo un problema de codificación de uno de calidad de imagen?

Mira la respuesta: si es un galimatías sin relación con la imagen, el fallo está en la codificación base64; si se parece pero cambia un carácter, es calidad de imagen y toca preprocesar.

¿Es necesario preprocesar todas las imágenes?

No. CaptchaAI lee bien los CAPTCHA de imagen estándar sin ningún preprocesamiento. Reserva el ampliado, el enfoque y el contraste para imágenes muy pequeñas o de bajo contraste; en el resto, procesar de más empeora la lectura.

¿Puedo reportar una respuesta incorrecta y recuperar el saldo?

Sí. Usa el endpoint reportbad con el ID de la tarea para informar de respuestas incorrectas. Ayuda a mejorar la precisión y puede acreditar saldo en tu cuenta.

¿Sirve de algo ampliar un CAPTCHA muy pequeño?

En imágenes por debajo de unos 200 px de ancho, sí: reescalar con un filtro de buena calidad y subir el contraste le da al OCR más detalle. Por encima de ese tamaño, ampliar ya no aporta.


Guías relacionadas


Resuelve tus CAPTCHA de imagen con precisión — prueba CaptchaAI.

Los comentarios están deshabilitados para este artículo.