دروس API

استراتيجيات حل CAPTCHA الصور متعددة الأحرف

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

تعتمد اختبارات CAPTCHA النصية بالصور على أساليب تُربك محرّكات التعرف الضوئي على الحروف (OCR) التقليدية: أحرف يلامس بعضها بعضًا، خطوط شطب تعبر النص، خلفيات مليئة بالنقاط، وخطوط طباعة متغيّرة بين حرف وآخر. هذه الحيل بسيطة على العين البشرية لكنها قاسية على السكربتات، ولهذا يجمع CaptchaAI بين نماذج مدرَّبة على أكثر من 27,500 نمط صورة وبين ضبط دقيق تتحكم فيه أنت عبر التلميحات.

تخيّل فريقًا في القاهرة أو الرياض يبني أداة لمراقبة توافر المنتجات وأسعارها على بوابة موردين إقليمية قديمة لا تزال تحمي نماذجها بـ CAPTCHA نصية بالصور. جمع هذه البيانات العامة لأغراض اختبار الجودة والمتابعة المصرّح بها يتوقف على قراءة تلك الصور قراءة موثوقة ومستقرة؛ وأي أخطاء متكررة في القراءة تكسر خط الأتمتة بأكمله. الأمثلة التالية مبنية حول هذا النوع من العمل العملي.


لماذا تصعب قراءة هذه الصور

تختلف صعوبة الصورة باختلاف الأسلوب المستخدم للتشويش. من المفيد تصنيف ما تواجهه قبل اختيار التلميحات المناسبة، لأن كل نوع يستفيد من إعداد مختلف:

النوع الوصف الصعوبة
نص نظيف بلا تشويه، خط موحّد سهل
نص مشوَّه أحرف مُدارة أو مُتغيّرة الحجم فرديًا متوسط
أحرف متصلة الأحرف تتلامس أو تتداخل صعب
خطوط متعددة خط مختلف لكل حرف صعب
ضوضاء وخطوط ضوضاء خلفية وخطوط شطب متوسط
تباين الألوان لون مختلف لكل حرف متوسط
تعبير رياضي أرقام وعوامل، والمطلوب هو الناتج متوسط

كلما اقتربت الصورة من الأسفل في هذا الجدول قلّ اعتمادك على القراءة المباشرة وزاد اعتمادك على وصف التحدي عبر textinstructions وضبط طول النص المتوقع.


الخطوة الأولى: إرسال الصورة واستطلاع النتيجة

الأساس لكل ما يليه هو دالة واحدة ترسل الصورة ثم تستطلع النتيجة دوريًا. أرسِل الصورة مُرمّزة base64 عبر نقطة النهاية in.php، واحفظ معرّف المهمة، ثم استفسر عن النتيجة من res.php حتى تتحول الحالة إلى جاهزة:

import requests
import base64
import time
import os

API_KEY = os.environ["CAPTCHAAI_API_KEY"]


def solve_complex_image(image_b64, hints=None):
    """Solve a complex multi-character image CAPTCHA."""
    payload = {
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "json": 1,
    }

    if hints:
        payload.update(hints)

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

    if result.get("status") != 1:
        raise RuntimeError(f"Submit failed: {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")

المعامل hints هو موضع القوة هنا: عبره تمرّر وصفًا للتحدي. أكثر المفاتيح فائدةً هي textinstructions لتعليمات نصية حرة، وminLen/maxLen لحصر طول النص المتوقع، وregsense لحساسية حالة الأحرف، وlanguage لتحديد مجموعة الأحرف، وnumeric وcalc للحالات الرقمية والحسابية. كلما كان الوصف أدقّ قلّ احتمال الخطأ في القراءة.


معالجة الأحرف المتصلة والمتداخلة

الأحرف المتصلة هي أصعب حالة على محرّكات OCR الأساسية لأنها تفشل في فصل الحدود بين الأحرف، لكن وصفها صراحةً يوجّه الخدمة إلى التعامل معها بشكل صحيح. مرّر تعليمات تشير إلى احتمال التلامس، وحدّد نطاق الطول لتقليص مساحة التخمين:

def solve_connected_letters(image_path):
    """Solve CAPTCHA with connected/overlapping characters."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "textinstructions": "Characters may be connected or overlapping",
        "minLen": 4,
        "maxLen": 8,
    })

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


الحالة المختلطة مع الضوضاء

حين تجمع الصورة بين حروف كبيرة وصغيرة وخلفية مزدحمة بالنقاط والخطوط، عرّف مجموعة الأحرف وفعّل حساسية الحالة حتى لا تُدمج الحروف المتشابهة شكلًا. المعامل regsense=1 يحافظ على التمييز بين الحرف الكبير والصغير، وlanguage=2 يحصر القراءة في الأحرف اللاتينية:

def solve_noisy_mixed(image_path):
    """Solve CAPTCHA with background noise and mixed case."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "regsense": 1,         # Case-sensitive
        "language": 2,         # Latin characters
        "textinstructions": "Ignore background lines and noise",
    })

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


النصوص متعددة الخطوط

بعض المواقع تستخدم خطًا مختلفًا لكل حرف لكسر أي افتراض عن شكل موحّد. عرّف هذه الحالة صراحةً حتى لا تُعامَل الاختلافات الشكلية على أنها أحرف مختلفة:

def solve_multi_font(image_path):
    """Solve CAPTCHA using multiple fonts per character."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "textinstructions": "Each character may use a different font or style",
        "minLen": 5,
        "maxLen": 7,
    })

اجمع دائمًا بين الوصف النصي وحصر الطول؛ فهذان المعاملان معًا يمنحان الخدمة إطارًا واضحًا حتى مع أكثر الخطوط تباينًا.


المعالجة المسبقة للصورة عند الحاجة

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

# preprocess.py
from PIL import Image, ImageFilter, ImageEnhance
import io
import base64


def preprocess_for_ocr(image_path):
    """Preprocess image to improve OCR accuracy."""
    img = Image.open(image_path)

    # Convert to grayscale
    img = img.convert("L")

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

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

    # Binarize (threshold)
    threshold = 128
    img = img.point(lambda p: 255 if p > threshold else 0)

    # Encode back to base64
    buffer = io.BytesIO()
    img.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode("ascii")

انتبه إلى أن المعالجة المبالَغ فيها قد تضرّ أكثر مما تنفع: قيمة عتبة (threshold) عدوانية قد تمحو أجزاءً رفيعة من الأحرف. اختبر إعداداتك على عيّنة صور حقيقية قبل تعميمها على خط الإنتاج.


إعادة المحاولة والإبلاغ عن الأخطاء

بدل الاعتماد على محاولة واحدة، تدرّج عبر مجموعة من الاستراتيجيات الاحتياطية: ابدأ بالتلميحات الكاملة، ثم جرّبها بلا تعليمات، ثم بقيود مخفّفة. وحين تعود إجابة خاطئة، أبلِغ عنها عبر reportbad لتغذية تحسين النموذج:

# retry_strategy.py


def solve_with_retry(image_b64, hints, max_retries=3):
    """Retry solving with fallback strategies."""
    strategies = [
        hints,                                          # Original hints
        {**hints, "textinstructions": ""},              # Without instructions
        {**hints, "numeric": 0, "regsense": 0},        # Relaxed constraints
    ]

    for i, strategy in enumerate(strategies[:max_retries]):
        try:
            result = solve_complex_image(image_b64, strategy)
            return {"text": result, "strategy": i, "success": True}
        except RuntimeError:
            continue

    return {"text": None, "strategy": -1, "success": False}


def report_bad_answer(task_id):
    """Report incorrect answer for quality feedback."""
    requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "reportbad",
        "id": task_id,
    }, timeout=10)

الإبلاغ المنتظم عن الإجابات الخاطئة ليس إجراءً شكليًا؛ فهو أكثر ما يرفع الدقّة على المواقع ذات الخطوط الخاصة التي تفشل بنمط ثابت.


جدول استكشاف الأخطاء

عند ظهور أخطاء متكررة، ابدأ بتشخيص العَرَض ثم طبّق الإجراء المقابل:

المشكلة السبب المحتمل الحل
أحرف ناقصة الأحرف المتصلة تُقرأ خطأً أضِف textinstructions يصف تلامس الأحرف
أحرف زائدة تفسير الضوضاء على أنها نص عالِج الصورة مسبقًا لإزالة الضوضاء قبل الإرسال
حالة أحرف خاطئة لم تُحفظ حالة الأحرف اضبط regsense=1
ناتج المعادلة يعود كتعبير غياب calc=1 فعّل وضع الحساب لكابتشا الرياضيات
خطأ متكرر على موقع محدّد خط طباعة خاص بالموقع أبلِغ عن الإجابات الخاطئة لتحسين النموذج

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

كيف أرفع دقّة الحل عندما تتلامس الأحرف أو تتداخل؟

صِف الحالة صراحةً عبر textinstructions مع تحديد minLen وmaxLen. حصر الطول المتوقع يمنع الخدمة من دمج حرفين متلامسين في حرف واحد أو تقسيم حرف واحد إلى اثنين.

كيف أتعامل مع كابتشا الحساب التي تعرض معادلة رياضية؟

فعّل وضع الحساب بتمرير calc=1 في التلميحات. بدون هذا المعامل قد تعود الخدمة بنص المعادلة نفسه (مثل "3+5") بدل الناتج المطلوب.

ما أقصى عدد أحرف تستطيع الخدمة قراءته في الصورة الواحدة؟

يتعامل CaptchaAI مع صور يصل طولها إلى نحو 20 حرفًا، رغم أن الغالبية العظمى من هذه الاختبارات تتراوح بين 4 و8 أحرف.

كم يستغرق حل صورة CAPTCHA نصية عادةً؟

تُحل صور CAPTCHA النصية عادةً في أقل من نصف ثانية وبمعدل نجاح مرتفع على الأنواع المدعومة. تكاليف الشبكة والاستطلاع الدوري في المثال أعلاه هي ما يضيف الجزء الأكبر من زمن الاستجابة الفعلي.


أدلة ذات صلة


جاهز للتعامل مع أصعب صور CAPTCHA النصية؟ ابدأ مع CaptchaAI.

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