دروس API

حل CAPTCHA الرياضية باستخدام معامل calc في CaptchaAI

حين يصطدم سكربت الأتمتة بنموذج يطلب ناتج معادلة مثل 7 + 5، فالمطلوب هو الرقم 12 لا نص المعادلة نفسه. هنا يتدخّل معامل calc: عند ضبطه على 1 يقرأ CaptchaAI الصورة، ينفّذ العملية الحسابية، ويعيد لك الناتج جاهزاً للإدخال المباشر في الحقل. وعند تركه على 0 تحصل على نص المعادلة كما هو لتتولى حسابه محلياً. يشرح هذا الدليل متى تختار كل وضع، وكيف تتعامل مع الكسور والأرقام السالبة والصيغ النصية، مع أمثلة Python جاهزة للنسخ.


أين تظهر الكابتشا الحسابية ولماذا

تنتشر الكابتشا الحسابية في مواضع كثيرة لأنها رخيصة التنفيذ ولا تتطلب خدمة خارجية، ومنها:

  • نماذج التسجيل وصفحات الدخول في المواقع الصغيرة والمتوسطة.
  • منتديات ووردبريس والإضافات المجانية لمكافحة الرسائل المزعجة.
  • البوابات الخدمية والحكومية في المنطقة العربية التي تعتمد تحققاً بسيطاً.
  • نماذج التعليقات والاشتراك في النشرات البريدية.

في كل هذه الحالات تعرض الصورة معادلة بسيطة — جمع أو طرح أو ضرب — ويُطلب من الزائر إدخال الناتج قبل قبول النموذج.

بالنسبة لمهندس استخراج البيانات أو مختبِر الجودة، تمثّل هذه المعادلة عقبة صغيرة لكنها متكررة: كل طلب يحتاج ناتجاً صحيحاً وإلا رُفض الإرسال. تحويل قراءة المعادلة وحسابها إلى نداء API واحد عبر معامل calc يجنّبك كتابة منطق تحليل هشّ كان سيتعطّل مع أول تغيير في نوع الخط أو تشويش الصورة.


كيف يعمل معامل calc

يقبل المعامل قيمتين فقط، وسلوكه مباشر ولا لبس فيه:

قيمة الحساب السلوك
0 (افتراضي) إرجاع النص كما هو (على سبيل المثال، "3+7")
1 يحسب النتيجة ويعيدها (على سبيل المثال، "10")

القاعدة العملية بسيطة:

  • إن كان الحقل يتوقع رقماً، فعّل calc=1 ليصلك الناتج جاهزاً.
  • أضف numeric=1 لتوجيه المحرك إلى أن الناتج المنتظر رقم، ما يقلّل الالتباس بين الحرف O والصفر أو بين l والواحد.
  • أبقِ calc=0 فقط حين تحتاج نص المعادلة نفسه لتطبيق منطق تحقق خاص قبل الحساب.

حل الكابتشا الحسابية: المثال الأساسي

يبدأ كل حل بإرسال الصورة المُرمّزة بصيغة base64 إلى نقطة النهاية in.php، ثم استطلاع res.php دورياً حتى يجهز الناتج. يرسل المثال التالي الطلب بـ calc=1، وينتظر ثماني ثوانٍ قبل أول استفسار — فالكابتشا الحسابية تُحل بسرعة عادةً، وترك فسحة أولية يوفّر طلبات لا داعي لها — ثم يستطلع كل خمس ثوانٍ. الرسالة CAPCHA_NOT_READY طبيعية وتعني أن الحل ما زال جارياً، وليست خطأً يستوجب التوقف.

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"

تنسيقات الكابتشا الحسابية الشائعة

لا تقتصر المعادلات على الجمع؛ يتعامل CaptchaAI مع العمليات الأربع الأساسية إضافة إلى بعض الصيغ النصية. يوضّح الجدول التالي أنماطاً شائعة والناتج المتوقع لكل منها، وهو مرجع سريع يساعدك على معرفة ما إذا كان الحقل يتوقع رقماً صحيحاً أم قد يأتي بناتج عشري:

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

حين يكون تخطيط المعادلة غير معتاد — أرقام متداخلة مع نص، أو رموز غير قياسية، أو عبارة مثل «مجموع الرقمين» — تساعد textinstructions في توضيح المطلوب للمحرك بلغة طبيعية. أضف الوصف إلى الحمولة نفسها ليعرف المحرك أنه أمام عملية حسابية لا مجرد نص للقراءة:

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 رقماً صالحاً، تعيد الطلب بـ calc=0 لالتقاط نص المعادلة وتحسبه محلياً عبر مقيّم يرفض أي رموز خارج الأرقام والعمليات الأساسية.

# 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

التدفق الكامل داخل المتصفح

لنفترض أنك تؤتمت اختبار جودة على بوابة تسجيل إقليمية تعرض معادلة مثل 4 + 9 قبل قبول النموذج، وتريد التأكد من أن مسار التسجيل يعمل عبر آلاف الحالات. تجمع الدالة التالية كل الخطوات في مكان واحد بالترتيب:

  1. التقاط صورة الكابتشا من الصفحة عبر Selenium.
  2. إرسالها للحل بـ calc=1 واستقبال الناتج 13.
  3. كتابة الناتج في حقل الإجابة ثم الضغط على زر الإرسال.

هذا هو نمط التكامل المعتمد الذي ستكرّره في معظم مشاريع الأتمتة:

# 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",
)

استكشاف الأخطاء وإصلاحها

معظم مشكلات الكابتشا الحسابية تعود إلى سببين: غياب calc=1 فيعود نص المعادلة بدل ناتجها، أو قراءة خاطئة لعامل التشغيل. يلخّص الجدول التالي الأعراض الأكثر شيوعاً وإجراء الإصلاح لكل منها:

المشكلة السبب الإجراء
إرجاع التعبير بدلاً من النتيجة calc=1 مفقود أضف calc=1 إلى الإرسال
نتيجة خاطئة أخطأ عامل التشغيل في القراءة (— vs +) أضف textinstructions واصفًا تنسيق المعادلة
إرجاع العلامة العشرية للمعادلة الصحيحة النقطة العائمة حوّل الناتج إلى عدد صحيح: str(int(float(result)))
ERROR_CAPTCHA_UNSOLVABLE معادلة مشوهة جداً حاول معالجة الصورة أولاً

الأسئلة الشائعة

متى أستخدم calc=0 بدلاً من calc=1؟

اختر calc=0 عندما تريد نص المعادلة كما هو — مثلاً لتسجيله أو لتطبيق منطق تحقق خاص قبل الحساب — أو حين تحتوي المعادلة على أقواس أو أسس تتجاوز العمليات الأساسية، فتحسبها محلياً بمقيّم آمن. في بقية الحالات يبقى calc=1 الخيار الأسرع والأقل عرضة للأخطاء.

هل يزيد تفعيل calc من تكلفة الطلب أو زمنه؟

لا. تسعير CaptchaAI قائم على عدد الـ Threads المتزامنة لا على نوع المعالجة، وكل خطة تشمل عدداً غير محدود من عمليات الحل ضمن حصتها من الـ Threads. تبدأ الخطط من BASIC بسعر $15 شهرياً و5 Threads، فلا رسوم إضافية مقابل تفعيل الحساب داخل الطلب.

لماذا يعيد المحرك عامل التشغيل خطأً أحياناً وكيف أصلحه؟

حين تكون الصورة مشوّشة قد يُقرأ × على أنه + أو تُخلط علامة الطرح. الحل هو تمرير textinstructions يصف تنسيق المعادلة صراحةً، أو الرجوع إلى calc=0 والتحقق من التعبير قبل حسابه محلياً للحصول على ناتج موثوق.

هل يتعامل calc مع النواتج العشرية والكسور؟

نعم، لكن القسمة قد تُنتج عدداً عشرياً حتى لو كان الناتج المتوقع صحيحاً بسبب الفاصلة العائمة. طبّق تنظيفاً بسيطاً مثل str(int(float(result))) عندما يتطلب الحقل رقماً صحيحاً، أو احتفظ بالصيغة العشرية إن كان النموذج يقبلها.


أدلة ذات صلة


حوّل كل معادلة إلى ناتج رقمي بنداء API واحد — ابدأ مع CaptchaAI.

التعليقات غير مفعّلة لهذا المقال.