دروس API

حل أنواع CAPTCHA المخصصة وغير القياسية مع CaptchaAI

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

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


متى تلجأ إلى أسلوب «الصورة مع تعليمات»؟

يوفّر CaptchaAI طرقاً مخصّصة للأنواع المعروفة: reCAPTCHA v2/v3، وCloudflare Turnstile وChallenge، وGeeTest v3، والصور/OCR والشبكات وBLS، مع دعم CaptchaFox وFriendly Captcha وLemin في مرحلة beta. لكن كثيراً من المواقع الإقليمية تبني أدوات تحقّق خاصة بها لا تندرج تحت أي طريقة مُسمّاة. هنا يبرز دور أسلوب «الصورة مع تعليمات»: بدل انتظار طريقة جاهزة لكل شكل جديد، تلتقط التحدي كصورة وتصف المطلوب بالكلمات، فتغطّي بذلك أي تحدٍّ مرئي قابل للالتقاط بلقطة شاشة.

يناسب هذا الأسلوب ثلاث حالات تحديداً:

  • تحدٍّ مرئي فريد لموقع واحد لا طريقة مُسمّاة له.
  • نوع جديد أو نادر لم تصدر له طريقة مخصّصة بعد.
  • واجهة تتغيّر كثيراً وتحتاج وصفاً مرناً بدل قواعد ثابتة.

فالنموذج لا يحتاج معرفة مسبقة بالموقع؛ يكفي أن يرى الصورة ويقرأ تعليماتك ليعيد قيمة محدّدة، وكلما دقّت التعليمات نظُف الناتج وسهُل تحليله برمجياً.


كيف تتعرّف على نوع الكابتشا المخصص؟

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

النوع السلوك طريقة التعامل
شريط التمرير (Slider) يُسحب إلى موضع محدّد لقطة شاشة + تعليمات نصية
لغز تركيب (Puzzle) تُسحب القطعة لتتطابق يُعالَج بأسلوب مشابه لحلول GeeTest
كابتشا صوتية استماع وكتابة الحروف إرسال الملف الصوتي
تدوير الصورة ضبط الاتجاه الصحيح لقطة شاشة + تعليمات
الاختيار بالترتيب نقر العناصر بتسلسل أسلوب شبكة الصور
معادلة حسابية حل عملية حسابية المعلمة calc=1
أداة تفاعلية خاصة Widget بلغة JavaScript خاص بالموقع لقطة شاشة + تعليمات نصية

الدالة الأساسية: إرسال أي صورة مع تعليمات

كل الأمثلة اللاحقة تستدعي هذه الدالة التي تعمل على مرحلتين:

  • الإرسال: ترفع الصورة المُرمّزة بصيغة base64 مع حقل textinstructions إلى in.php.
  • الاستطلاع: تستفسر عن النتيجة من res.php حتى تجهز الإجابة أو تنتهي المهلة.
import requests
import base64
import time
import os

API_KEY = os.environ["CAPTCHAAI_API_KEY"]


def solve_custom_captcha(image_b64, instructions):
    """Solve any visual CAPTCHA using image + text instructions."""
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "textinstructions": instructions,
        "json": 1,
    }, timeout=30)

    result = resp.json()
    if result.get("status") != 1:
        raise RuntimeError(result.get("request"))

    task_id = result["request"]

    time.sleep(10)
    for _ in range(30):
        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")

تبقى الدالة محايدة تجاه نوع التحدي: تتغيّر التعليمات فقط بينما يثبت مسار الإرسال والاستطلاع.


كابتشا شريط التمرير

في هذا النوع يجب سحب المقبض إلى موضع محدّد. نلتقط التحدي كصورة، ونطلب من الخدمة إزاحة الـ X بالبكسل فقط، ثم نحرّك المقبض بهذا المقدار عبر ActionChains:

# slider_captcha.py
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains


def solve_slider_captcha(driver, captcha_selector):
    """Screenshot slider CAPTCHA and solve via CaptchaAI."""
    captcha = driver.find_element(By.CSS_SELECTOR, captcha_selector)
    image_b64 = captcha.screenshot_as_base64

    result = solve_custom_captcha(
        image_b64,
        "What pixel position should the slider be dragged to? "
        "Return only the X offset number."
    )

    try:
        offset = int(result)
    except ValueError:
        return False

    # Drag slider to position
    slider = driver.find_element(By.CSS_SELECTOR, ".slider-handle")
    ActionChains(driver).click_and_hold(slider).move_by_offset(offset, 0).release().perform()

    return True

صياغة «أعِد رقم إزاحة الـ X فقط» تمنع إرجاع وصف نصّي يصعب تحويله إلى عدد.


كابتشا التدوير

هنا يجب تدوير الصورة إلى اتجاهها الصحيح، والمنطق خطوتان:

  • اسأل عن عدد الدرجات المطلوب تدويرها في اتجاه عقارب الساعة.
  • اضغط زر التدوير بعدد النقرات المناسب، وكل نقرة تعادل ٩٠ درجة.
# rotation_captcha.py


def solve_rotation_captcha(driver, captcha_selector):
    """Solve rotation CAPTCHA."""
    captcha = driver.find_element(By.CSS_SELECTOR, captcha_selector)
    image_b64 = captcha.screenshot_as_base64

    result = solve_custom_captcha(
        image_b64,
        "How many degrees should this image be rotated clockwise "
        "to be in the correct upright orientation? Return only the number."
    )

    try:
        degrees = int(result)
    except ValueError:
        return False

    # Click rotation button the correct number of times
    rotate_btn = driver.find_element(By.CSS_SELECTOR, ".rotate-button")
    clicks = degrees // 90  # Each click rotates 90 degrees

    for _ in range(clicks):
        rotate_btn.click()
        time.sleep(0.3)

    return True

كابتشا الاختيار بالترتيب

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

# order_captcha.py


def solve_order_captcha(driver, captcha_selector, item_selector):
    """Solve click-in-order CAPTCHA."""
    captcha = driver.find_element(By.CSS_SELECTOR, captcha_selector)
    image_b64 = captcha.screenshot_as_base64

    result = solve_custom_captcha(
        image_b64,
        "What is the correct order? Return as comma-separated "
        "numbers (1-indexed) representing positions left-to-right, top-to-bottom."
    )

    # Parse order
    try:
        order = [int(x.strip()) for x in result.split(",")]
    except ValueError:
        return False

    # Click items in order
    items = driver.find_elements(By.CSS_SELECTOR, item_selector)
    for idx in order:
        if 1 <= idx <= len(items):
            items[idx - 1].click()
            time.sleep(0.5)

    return True

الكابتشا الصوتية

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

# audio_captcha.py
import requests


def solve_audio_captcha(audio_url):
    """Download and solve an audio CAPTCHA."""
    # Download audio
    resp = requests.get(audio_url, timeout=30)
    audio_b64 = base64.b64encode(resp.content).decode("ascii")

    # Submit as image with instructions
    # CaptchaAI may support audio via the base64 method
    result = solve_custom_captcha(
        audio_b64,
        "This is an audio CAPTCHA. Transcribe the spoken characters."
    )
    return result

أدوات الكابتشا المخصصة بالكامل

أصعب الحالات هي الأدوات التي يبنيها الموقع من الصفر بلا نمط معروف. يتكوّن النهج العام من أربع خطوات ثابتة:

  1. التقط الأداة كاملةً كصورة.
  2. اقرأ أي تعليمات ظاهرة على الشاشة.
  3. أرسل الصورة مع وصف دقيق للمطلوب.
  4. أدخِل الناتج في حقل الإدخال، أو عبّئه عبر JavaScript إن لم يوجد حقل مباشر.
# custom_widget.py
from selenium import webdriver
from selenium.webdriver.common.by import By


def handle_custom_widget(driver, widget_selector):
    """Handle an unknown custom CAPTCHA widget."""

    # Step 1: Screenshot the entire widget
    widget = driver.find_element(By.CSS_SELECTOR, widget_selector)
    image_b64 = widget.screenshot_as_base64

    # Step 2: Get any visible instructions
    try:
        instructions_el = widget.find_element(By.CSS_SELECTOR, ".instructions, .prompt, p")
        visible_instructions = instructions_el.text
    except Exception:
        visible_instructions = "Solve this CAPTCHA"

    # Step 3: Submit with descriptive instructions
    result = solve_custom_captcha(
        image_b64,
        f"CAPTCHA instructions: {visible_instructions}. "
        f"Return the answer text."
    )

    # Step 4: Try to submit result
    try:
        input_el = widget.find_element(By.CSS_SELECTOR, "input")
        input_el.clear()
        input_el.send_keys(result)
    except Exception:
        # No input — try clicking based on result
        driver.execute_script("""
            var input = document.querySelector('input[name*="captcha"]');
            if (input) input.value = arguments[0];
        """, result)

    return result

قراءة التعليمات الظاهرة تلقائياً تجعل الدالة تتكيّف مع صياغات مختلفة دون تعديل الكود.


الكشف التلقائي عن نوع الكابتشا

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

# detector.py
import re


def detect_captcha_type(page_html):
    """Detect which CAPTCHA type is on a page."""
    checks = {
        "recaptcha_v2": r'data-sitekey.*g-recaptcha',
        "recaptcha_v3": r'recaptcha/api\.js\?render=',
        "turnstile": r'cf-turnstile|challenges\.cloudflare\.com/turnstile',
        "geetest": r'gt\b.*challenge|geetest',
        "bls": r'method.*bls|bls-captcha',
        "image_text": r'captcha.*\.(png|jpg|gif|jpeg)',
        "slider": r'slider.*captcha|slide.*verify',
        "audio": r'audio.*captcha|captcha.*audio',
    }

    detected = []
    for captcha_type, pattern in checks.items():
        if re.search(pattern, page_html, re.IGNORECASE):
            detected.append(captcha_type)

    return detected if detected else ["unknown"]

فصل الكشف عن الحل هو ما يجعل السكربت مرناً: تتغيّر الواجهة، لكن منطق التوجيه يبقى ثابتاً.


سيناريو تطبيقي: اختبار متجر إقليمي

تخيّل أنك مسؤول ضمان الجودة في متجر إلكتروني يخدم السوق الخليجي، ومهمتك تشغيل اختبارات آلية على تدفق إتمام الشراء كل ليلة. في إحدى الخطوات يظهر شريط تمرير للتحقق مع تعليمات مكتوبة بالعربية مثل «اسحب القطعة لإكمال الصورة». بدل أن يتعطّل الاختبار عند هذه النقطة، تلتقط الأداة لقطة شاشة للتحدي وترسلها عبر solve_custom_captcha مع تعليمات صريحة تطلب موضع الـ X بالبكسل، ثم تحرّك المقبض بالمقدار المُعاد.

وبما أن CaptchaAI يعتمد تسعيراً قائماً على الـ threads — تبدأ خطة BASIC من 15 دولاراً شهرياً بخمسة threads وحلول غير محدودة لكل thread — يمكنك تشغيل عدة اختبارات ليلية بالتوازي دون رسوم لكل عملية حل. وعند نمو عمليات التحقّق المتزامنة، ارفع عدد الـ threads بالانتقال إلى خطة أعلى.


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

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

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

متى أستخدم أسلوب «الصورة مع تعليمات» بدلاً من طريقة مخصّصة لنوع محدّد؟

استخدمه عندما لا يطابق التحدي أي نوع مدعوم رسمياً، أو حين يكون مرئياً وفريداً لموقع واحد كشريط التمرير أو التدوير أو اللغز أو أداة JavaScript خاصة. أما إن كان التحدي من عائلة معروفة مثل reCAPTCHA v2/v3 أو Cloudflare Turnstile أو GeeTest v3، فاستدعِ طريقتها المخصّصة لأنها أدقّ وأسرع.

كيف أصيغ التعليمات النصية لأحصل على إجابة قابلة للتحليل برمجياً؟

اتبع ثلاث قواعد تجعل الناتج قابلاً للتحليل مباشرة:

  • اطلب القيمة فقط: «أعِد الرقم فقط» أو «أعِد المواضع مفصولة بفواصل».
  • حدّد الوحدة صراحةً داخل النص: بكسل أو درجة أو ترتيب.
  • تجنّب الصياغة الغامضة التي تدفع الخدمة لإرجاع وصف بدل قيمة، فيفشل تحويلها إلى int أو تقسيمها.

هل تندرج hCaptcha وFunCaptcha وGeeTest v4 ضمن أنواع الكابتشا المدعومة؟

لا. hCaptcha وFunCaptcha (Arkose Labs) غير مدعومَين حالياً، ودعم GeeTest v4 «قادم قريباً» وغير متاح بعد. المدعوم فعلياً يشمل reCAPTCHA v2/v3، وCloudflare Turnstile وChallenge، وGeeTest v3، والصور/OCR والشبكات وBLS، إضافة إلى CaptchaFox وFriendly Captcha وLemin في مرحلة beta. وأسلوب «الصورة مع تعليمات» لا يحوّل نوعاً غير مدعوم إلى مدعوم؛ فهو مخصّص للتحديات المرئية الجديدة القابلة للالتقاط بلقطة شاشة.

ماذا أفعل إذا كانت الأداة المخصصة تتغيّر باستمرار؟

مرّر مصدر الصفحة أولاً عبر دالة detect_captcha_type لتحديد التحدي الظاهر حالياً، ثم وجّه التنفيذ إلى الدالة المناسبة. هذا الفصل بين الكشف والحل يجعل السكربت يصمد أمام تغيّرات الواجهة بدل أن ينكسر مع كل تعديل في الموقع.


أدلة ذات صلة


حل أي اختبار CAPTCHA — ابدأ مع CaptchaAI.

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