API Tutorials

Математическое решение CAPTCHA с параметром расчета CaptchaAI

Скрипт отправил математическую 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-регламентов.

Если тестовых сценариев много и браузерные инстансы запускаются параллельно, тариф стоит выбирать по числу одновременных потоков:

  1. Последовательные прогоны на одном раннере — хватает BASIC ($15/мес, 5 потоков).
  2. 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.

Комментарии для этой статьи отключены.