Si tu script envía "3+7" cuando el formulario esperaba "10", el problema no es el OCR: es que estás mandando el texto de la ecuación en vez del resultado. Ese es el error número uno con los CAPTCHA aritméticos, y se corrige con un solo campo. El parámetro calc=1 le indica a CaptchaAI que, además de leer la imagen, haga la operación y te devuelva el número ya calculado. Sin ese campo, el API se limita a transcribir lo que ve.
Un CAPTCHA matemático no es más que un desafío tipo image/OCR con un paso extra: muestra una expresión (4 × 6 = ?, 20 ÷ 5, o incluso "tres más cinco" en letra) y el sitio quiere la respuesta numérica en la casilla. CaptchaAI resuelve este tipo de forma nativa, así que no necesitas montar tu propio motor de reconocimiento ni un evaluador de expresiones aparte para el caso habitual.
Qué hace el parámetro calc
El comportamiento se reduce a un interruptor. Con calc=0 recibes la transcripción literal; con calc=1, el resultado.
Valor de calc |
Comportamiento |
|---|---|
0 (predeterminado) |
Devuelve el texto tal cual (por ejemplo, "3+7") |
1 |
Calcula el resultado y lo devuelve (por ejemplo, "10") |
La regla práctica: usa calc=1 siempre que el sitio pida el número, que es lo normal. Reserva calc=0 para los casos raros en los que necesitas ver la expresión original y hacer tú mismo la cuenta (más sobre esto en la sección de casos límite).
Resolver un CAPTCHA matemático básico
El flujo es el mismo de cualquier tarea OCR: envías la imagen en base64 a in.php con calc=1 y numeric=1, recibes un id y sondeas res.php hasta que el resultado esté listo. El campo numeric=1 refuerza que la respuesta esperada es un número, lo que reduce confusiones con caracteres parecidos.
import requests
import base64
import time
import os
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_math_captcha(image_b64):
"""Solve a math CAPTCHA — returns the computed result."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_b64,
"calc": 1, # Compute the math
"numeric": 1, # Result will be a number
"json": 1,
}, timeout=30)
result = resp.json()
if result.get("status") != 1:
raise RuntimeError(result.get("request"))
task_id = result["request"]
time.sleep(8)
for _ in range(24):
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(5)
raise TimeoutError("Solve timeout")
# Example: Image shows "3 + 7 = ?"
# With calc=0: Returns "3+7"
# With calc=1: Returns "10"
Fíjate en el patrón de sondeo: una primera espera de 8 segundos y luego reintentos cada 5, con un límite de 24 vueltas. Ese techo evita que un fallo de red deje el proceso colgado, y CAPCHA_NOT_READY (así, sin la segunda T, tal como lo devuelve el API) es la señal normal de "sigue trabajando, vuelve a consultar".
Formatos de CAPTCHA matemático que verás en la práctica
CaptchaAI cubre la aritmética básica en sus variantes habituales. Estos son los formatos que aparecen con más frecuencia y lo que devuelve cada uno:
Format Example Result
─────────────────────────────────────────
Addition 3 + 7 = ? 10
Subtraction 15 - 8 = ? 7
Multiplication 4 × 6 = ? 24
Division 20 ÷ 5 = ? 4
Mixed 3 + 4 × 2 = ? 11
Text-based "three plus five" 8
El caso 3 + 4 × 2 es un buen recordatorio de que la precedencia de operadores importa: la respuesta correcta es 11, no 14. Y el formato en letra ("three plus five") es donde más conviene apoyarse en instrucciones de texto, como veremos a continuación.
Añadir instrucciones de texto para formatos ambiguos
Cuando la ecuación viene con adornos, palabras o un orden poco común, una pista en lenguaje natural mejora la lectura. El campo textinstructions acompaña a la imagen y describe qué se espera.
def solve_text_math_captcha(image_b64, instructions):
"""Solve a math CAPTCHA with custom instructions."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_b64,
"calc": 1,
"textinstructions": instructions,
"json": 1,
}, timeout=30)
return resp.json()
# Example instructions:
# "Solve the math expression and enter the number"
# "What is the result of the equation shown?"
# "Enter the sum of the two numbers"
Manejo de casos límite
Los resultados negativos y los decimales son las dos fuentes clásicas de discrepancia entre lo que devuelve el API y lo que el formulario acepta. Un -3 con espacios, o un 4.0 donde el sitio quiere 4, provocan un rechazo silencioso. Conviene normalizar la respuesta antes de escribirla en la casilla, y tener un plan B: si por alguna razón el valor no es numérico, se pide la expresión con calc=0 y se evalúa localmente contra un patrón estricto.
# edge_cases.py
def validate_math_result(answer):
"""Validate and clean math CAPTCHA result."""
if not answer:
return None
# Remove spaces
answer = answer.strip()
# Handle negative results
if answer.startswith("-"):
try:
return str(int(answer))
except ValueError:
return answer
# Handle decimal results
try:
num = float(answer)
if num == int(num):
return str(int(num))
return str(num)
except ValueError:
return answer
def solve_math_with_fallback(image_b64):
"""Try calc=1, fall back to manual parsing if needed."""
# Try with calc
result = solve_math_captcha(image_b64)
# Validate result is actually a number
try:
float(result)
return result
except (ValueError, TypeError):
pass
# Fallback: solve without calc and compute locally
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_b64,
"calc": 0, # Get the expression text
"json": 1,
}, timeout=30)
# ... poll for result ...
expression = "3+7" # Example OCR result
# Safely evaluate
return str(safe_eval(expression))
def safe_eval(expression):
"""Safely evaluate a simple math expression."""
# Only allow digits and basic operators
import re
cleaned = expression.replace("×", "*").replace("÷", "/").replace("=", "").replace("?", "")
cleaned = cleaned.strip()
if not re.match(r'^[\d\s+\-*/().]+$', cleaned):
raise ValueError(f"Unsafe expression: {expression}")
return eval(cleaned) # Safe because we validated the pattern
Ese safe_eval solo evalúa la cadena después de comprobarla contra una expresión regular que permite únicamente dígitos, espacios y los operadores básicos. Es la diferencia entre calcular una suma y abrir la puerta a ejecución de código arbitrario: nunca pases a eval una cadena que no hayas validado antes.
Flujo completo con Selenium
En un scraper real, resolver el CAPTCHA es solo un paso. El patrón habitual es capturar la imagen del elemento en pantalla, mandarla a resolver, escribir el número en el campo correspondiente y enviar el formulario. Este es el caso típico al automatizar la revisión de un portal público de trámites o el QA de tu propio flujo de alta, donde la aritmética aparece justo antes del botón de enviar.
# full_flow.py
from selenium import webdriver
from selenium.webdriver.common.by import By
import base64
import os
def solve_math_captcha_on_page(driver, captcha_selector, input_selector, submit_selector):
"""Complete flow: capture math CAPTCHA, solve, enter answer."""
# Capture CAPTCHA image
captcha_el = driver.find_element(By.CSS_SELECTOR, captcha_selector)
image_b64 = captcha_el.screenshot_as_base64
# Solve with calc=1
answer = solve_math_captcha(image_b64)
print(f"Math answer: {answer}")
# Enter the computed result
input_el = driver.find_element(By.CSS_SELECTOR, input_selector)
input_el.clear()
input_el.send_keys(answer)
# Submit
driver.find_element(By.CSS_SELECTOR, submit_selector).click()
# Usage
driver = webdriver.Chrome()
driver.get("https://example.com/form")
solve_math_captcha_on_page(
driver,
captcha_selector="#captcha-image",
input_selector="#captcha-answer",
submit_selector="#submit-btn",
)
Un apunte de contexto para equipos de la región: cuando automatizas la monitorización de portales de administración electrónica —cita previa en España, trámites del SAT en México, gestiones de AFIP en Argentina— trabaja siempre sobre flujos que tengas autorización para automatizar y respeta los términos de servicio y la normativa de protección de datos aplicable. El código anterior es idéntico sea cual sea el sitio; lo que cambia es que la responsabilidad de usarlo bien es tuya.
Solución de problemas
| Problema | Causa | Solución |
|---|---|---|
| Devuelve la expresión en lugar del resultado | Falta calc=1 |
Añade calc=1 al envío |
| Resultado incorrecto | El operador se leyó mal (× vs +) | Añade textinstructions describiendo el formato de la ecuación |
| Devuelve decimal en una ecuación entera | Coma flotante | Convierte a entero: str(int(float(result))) |
ERROR_CAPTCHA_UNSOLVABLE |
Ecuación muy distorsionada | Prueba a preprocesar la imagen primero |
Preguntas frecuentes
¿Cuándo conviene usar calc=1 y cuándo calc=0?
Usa calc=1 siempre que el formulario pida el número, que es el caso normal. Recurre a calc=0 solo cuando necesites la expresión literal —por ejemplo, para registrar qué se mostró o para evaluar tú mismo una fórmula con paréntesis o exponentes que la aritmética básica no cubre.
¿En qué idioma escribo las textinstructions?
El inglés es lo más fiable, tal como aparece en los ejemplos ("Enter the sum of the two numbers"). Puedes probar instrucciones en español para formatos en letra, pero mantén las frases cortas y directas; los resultados con enunciados largos o ambiguos pueden variar.
¿Por qué me llega el resultado con decimales cuando la cuenta es entera?
Es un tema de formato, no de cálculo: una división puede devolverse como 4.0. Normaliza antes de escribir en el campo con str(int(float(result))), o reutiliza la función validate_math_result del ejemplo de casos límite, que ya distingue enteros de decimales.
¿Qué plan necesito si resuelvo muchos CAPTCHA matemáticos por hora?
CaptchaAI factura por thread concurrente, con resoluciones ilimitadas dentro del mes. Para empezar, el plan BASIC ($15/mes, 5 threads) cubre volúmenes de prueba; si tu scraper procesa varias colas en paralelo, sube a ADVANCE ($90/mes, 50 threads). El coste mensual fijo en USD es predecible frente al pago por resolución.
Guías relacionadas
Resuelve CAPTCHA matemáticos automáticamente. Empieza con CaptchaAI.