Скрипт отправил математическую CAPTCHA на решение и получил в ответ строку "3+7" вместо цифры 10? Это не сбой API — параметр calc в запросе к CaptchaAI по умолчанию выключен (calc=0), поэтому сервис возвращает распознанное выражение как есть, а не считает его. Достаточно одного параметра calc=1 в запросе к in.php: CaptchaAI сам вычисляет уравнение и отдаёт готовый результат, который можно сразу подставлять в поле ответа формы, без дополнительного парсинга на вашей стороне.
Как работает параметр calc: значения и логика ответа
По умолчанию OCR-движок CaptchaAI ведёт себя как обычное распознавание текста — он видит уравнение и возвращает его как строку. Чтобы получить именно вычисленный ответ, а не текст, нужно явно включить расчёт:
Значение calc |
Что возвращает API |
|---|---|
0 (по умолчанию) |
Текст как есть (например, "3+7"). |
1 |
Вычисленный результат (например, "10"). |
На практике calc=1 почти всегда стоит комбинировать с numeric=1 — так ответ приходит чистой числовой строкой без лишних символов, которую можно сразу писать в поле ввода формы.
Коротко, что меняет параметр:
calc=0(значение по умолчанию) — API отдаёт распознанный текст уравнения, вычислять придётся самостоятельно.calc=1— CaptchaAI считает результат сам и возвращает готовое число.numeric=1в паре сcalc=1— дополнительно страхует от пробелов и нечисловых символов в ответе.
Базовое решение математической CAPTCHA через API
Логика простая: отправляете изображение в base64 с calc=1, получаете task_id, опрашиваете res.php, пока не придёт готовый ответ. Каждый такой запрос занимает один поток из вашего тарифа CaptchaAI на всё время ожидания — это стоит учитывать при проектировании параллельных прогонов.
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"
Обратите внимание на цикл опроса: первая пауза — 8 секунд, затем до 24 попыток с интервалом 5 секунд, то есть в худшем случае ожидание может занять около двух минут. Для UI-форм с коротким тайм-аутом сессии закладывайте это время заранее, а не реагируйте на TimeoutError постфактум.
Пример из практики: приёмочное тестирование формы на staging
Допустим, вы — QA-инженер и проверяете форму регистрации на тестовом стенде перед релизом. На форме стоит математическая CAPTCHA, и ручной ввод ответа при каждом прогоне автотеста тормозит CI/CD. Задача решается тем же кодом: скриншот виджета уходит в CaptchaAI с calc=1, готовое число возвращается и подставляется в поле ответа через Selenium или Playwright.
Для таких прогонов используйте только сгенерированные тестовые данные, а не реальные персональные данные пользователей — это разумно и с точки зрения 152-ФЗ «О персональных данных», и по правилам большинства QA-регламентов.
Если тестовых сценариев много и браузерные инстансы запускаются параллельно, тариф стоит выбирать по числу одновременных потоков:
- Последовательные прогоны на одном раннере — хватает BASIC ($15/мес, 5 потоков).
- CI с 20+ параллельными инстансами — разумнее смотреть на ADVANCE ($90/мес, 50 потоков).
Форматы математических CAPTCHA, которые встречаются на практике
calc рассчитан на базовую арифметику — сложение, вычитание, умножение и деление, включая уравнения с несколькими действиями. Отдельно встречаются капчи, где условие записано словами («three plus five»), — их OCR тоже распознаёт, но качество вычисления может быть ниже, чем на цифровых примерах.
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
Текстовые инструкции для нестандартных капч
Если сайт использует нетиповое условие — уравнение в скобках, словесную формулировку или необычный порядок действий, — передайте textinstructions. Это подсказка для распознавания, а не отдельный режим расчёта, поэтому её стоит использовать вместе с calc=1, а не вместо него.
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"
Формулировка инструкции влияет на точность больше, чем кажется: чем конкретнее вы описываете, что показано на картинке, тем реже воркер (или модель распознавания) путает оператор.
Обработка отрицательных и дробных результатов
calc=1 возвращает и отрицательные числа, и десятичные дроби, если уравнение к этому ведёт. Прежде чем передавать ответ дальше в форму, стоит пропустить его через собственную валидацию — это защищает от лишних пробелов, случайного плавающего формата там, где ожидается целое число, и от ситуаций, когда основной способ дал нечисловой результат.
# 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
solve_math_with_fallback — рабочий паттерн для продакшена: если calc=1 по какой-то причине не дал чистое число, код переключается на calc=0 и досчитывает выражение локально. eval() в safe_eval безопасен только потому, что строка предварительно прогоняется через регулярное выражение, отсекающее всё, кроме цифр и базовых операторов, — не убирайте эту проверку, если переиспользуете функцию.
Полный сценарий: от скриншота до отправки формы
Ниже — сквозной пример с Selenium: захват элемента капчи, отправка в CaptchaAI, ввод ответа и сабмит формы. Такой же паттерн переносится на Playwright или Puppeteer — меняется только способ захвата скриншота элемента.
# 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",
)
Для headless-режима в CI поведение не меняется — важно лишь, чтобы captcha_selector действительно указывал на элемент с полностью отрисованным изображением к моменту скриншота, иначе OCR получит пустой или обрезанный кадр.
Типичные ошибки и как их избежать
Большинство проблем с calc сводится к четырём причинам — забытому параметру, неверно распознанному оператору, разнице между целым числом и дробью, а также сильно искажённому изображению.
| Проблема | Причина | Решение |
|---|---|---|
| Возвращается выражение вместо результата | Отсутствует calc=1 |
Добавьте calc=1 в тело запроса |
| Неверный результат | Оператор распознан неправильно (× вместо +) | Добавьте textinstructions с описанием формата уравнения |
| Возвращается дробное число вместо целого | Ответ пришёл как float | Приведите к целому: str(int(float(result))) |
ERROR_CAPTCHA_UNSOLVABLE |
Сильно искажённое уравнение | Предварительно обработайте изображение (контраст, шумоподавление) |
Часто задаваемые вопросы
Справится ли calc с выражением в скобках или с дробями?
calc=1 рассчитан на базовую арифметику — сложение, вычитание, умножение, деление. Для выражений со скобками, степенями или более сложной алгеброй надёжнее взять calc=0, получить исходный текст и посчитать его локально, как в примере с safe_eval выше.
Сколько времени в среднем занимает решение math CAPTCHA?
Судя по логике опроса в примере кода, воркер обычно успевает вернуть ответ в течение первых 8–15 секунд после отправки задачи; цикл опроса рассчитан на запас до двух минут на случай нагрузки. Закладывайте это время в тайм-ауты формы, а не сокращайте паузы между запросами к res.php — слишком частый опрос не ускоряет решение.
Обязательно ли указывать numeric=1 вместе с calc=1?
Не обязательно, но рекомендуется: numeric=1 отвечает за чисто числовую строку без пробелов и посторонних символов, а calc=1 — за само вычисление. Вместе они избавляют от лишней постобработки ответа перед вставкой в поле формы.
Что делать, если ответ приходит в разном формате между прогонами?
Не полагайтесь на сырую строку из res.php — прогоняйте её через собственную функцию нормализации вроде validate_math_result из примера выше: она обрезает пробелы, приводит дробные результаты с нулевой дробной частью к целым и корректно обрабатывает отрицательные числа.
Похожие руководства
Решайте математические CAPTCHA автоматически — начните с CaptchaAI.