دروس API

BLS CAPTCHA ترتيب الصور ومعالجة استجابة الشبكة

استجابة BLS CAPTCHA ليست قيمة نصية واحدة، بل قائمة من مؤشرات الخلايا تحدد أي صور نقرت وبأي ترتيب. وإذا أرسلتها بالتنسيق الخطأ — قناع نقطي بدل قائمة، أو ترتيب معكوس — يرفض الخادم الحل رغم أن الصور صحيحة. لذلك يبدأ التعامل مع شبكة BLS من فهم كيف تُرقّم الخلايا وكيف يتوقع الموقع استلام الحل، لا من الحل نفسه.

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


أنواع تحديات شبكة BLS: الترتيب والاختيار والمطابقة

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

ترتيب الصور

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

اختيار الصور المطابقة

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

مطابقة النمط

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

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

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


تخطيط الشبكة وربط الخلايا بالمؤشرات

قبل الحل تحتاج إلى دالة تحوّل بين موضع الخلية (صف، عمود) ومؤشرها المسطّح. تعتمد شبكات BLS غالباً تخطيط 3×3 أو 4×4، والترقيم يبدأ من الصفر في الزاوية العليا:

# grid_mapping.py

# BLS grids typically use 3x3 or 4x4 layouts
# Each cell maps to an index:

# 3x3 grid:
# [0] [1] [2]
# [3] [4] [5]
# [6] [7] [8]

# 4x4 grid:
#  [0]  [1]  [2]  [3]
#  [4]  [5]  [6]  [7]
#  [8]  [9] [10] [11]
# [12] [13] [14] [15]

def grid_position(index, cols=3):
    """Convert flat index to row, column."""
    return index // cols, index % cols


def index_from_position(row, col, cols=3):
    """Convert row, column to flat index."""
    return row * cols + col


# Example: For a 3x3 grid, position (1, 2) = index 5
print(grid_position(5, cols=3))   # (1, 2)
print(index_from_position(1, 2))  # 5

إرسال تحدي BLS إلى CaptchaAI واستلام النتيجة

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

# solve_bls_grid.py
import requests
import time
import os
import json


def solve_bls_grid(sitekey, pageurl, instructions=None):
    """Solve a BLS grid CAPTCHA and get response indices."""
    api_key = os.environ["CAPTCHAAI_API_KEY"]

    payload = {
        "key": api_key,
        "method": "bls",
        "sitekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }
    if instructions:
        payload["instructions"] = instructions

    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(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("BLS grid solve timeout")

يستقبل CaptchaAI التحدي من خوادم BLS ويحلّه عن بُعد؛ توفّر أنت مفتاح الموقع وعنوان URL فقط. لاحظ نمط الاستطلاع في الكود: مهلة أولية قدرها 10 ثوانٍ قبل أول استفسار، ثم حلقة تعيد السؤال كل 5 ثوانٍ. طالما عادت الاستجابة بالقيمة CAPCHA_NOT_READY فالحل ما زال قيد المعالجة؛ وأي قيمة أخرى غير النجاح تعني خطأً فعلياً يجب إيقاف المحاولة عنده بدل الاستمرار في الانتظار.


تحليل استجابة الشبكة وتحويلها إلى مؤشرات

قد تعود الاستجابة كمصفوفة JSON، أو مؤشرات مفصولة بفواصل، أو قيمة مفردة. الدالة التالية توحّدها في قائمة مؤشرات، وتحوّلها إلى قناع نقطي (bitmask) للمواقع التي تتوقعه:

# parse_response.py
import json


def parse_grid_response(solution):
    """Parse CaptchaAI BLS response into actionable grid data."""
    # Solution may be JSON or comma-separated indices
    if isinstance(solution, str):
        try:
            parsed = json.loads(solution)
            return parsed
        except json.JSONDecodeError:
            pass

        # Try comma-separated indices
        if "," in solution:
            return [int(x.strip()) for x in solution.split(",")]

        # Single value
        return [solution]

    return solution


def format_for_submission(indices, grid_size=9):
    """Format indices for form submission."""
    # Some sites expect a bitmask
    bitmask = ["0"] * grid_size
    for idx in indices:
        if isinstance(idx, int) and 0 <= idx < grid_size:
            bitmask[idx] = "1"

    return {
        "indices": indices,
        "bitmask": "".join(bitmask),
        "count": len(indices),
    }

الفرق جوهري: [0, 4, 8] تعدّد الخلايا المختارة، بينما "100010001" يمثّل الشبكة كلها بخانة لكل خلية. اختيار التنسيق الخطأ سبب شائع لرفض حلّ صحيح.


حقن الحل في الصفحة عبر Selenium

تحقن المؤشرات بإحدى طريقتين: النقر على الخلايا مباشرة، أو كتابة القيمة في حقل مخفي. القاعدة العملية بسيطة: إذا كانت الشبكة تتفاعل مع النقر البشري (خلايا قابلة للنقر) استخدم click_grid_cells، وإذا كان الموقع يقرأ الحل من حقل نموذج مخفي استخدم inject_hidden_response. لاحظ الفارق في التوقيت: تحديات الترتيب تحتاج مهلة أطول بين النقرات (نصف ثانية) من تحديات الاختيار (ثلث ثانية)، لأن التسلسل نفسه جزء من الإجابة:

# inject_grid.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time


def click_grid_cells(driver, indices):
    """Click specific grid cells based on solution indices."""
    wait = WebDriverWait(driver, 10)

    # Find all grid cells
    cells = wait.until(
        EC.presence_of_all_elements_located(
            (By.CSS_SELECTOR, ".captcha-grid .cell, .bls-grid img, .grid-item")
        )
    )

    for idx in indices:
        if isinstance(idx, int) and idx < len(cells):
            cells[idx].click()
            time.sleep(0.3)  # Brief delay between clicks


def set_order_sequence(driver, ordered_indices):
    """Click grid cells in the correct order for ordering challenges."""
    wait = WebDriverWait(driver, 10)

    cells = wait.until(
        EC.presence_of_all_elements_located(
            (By.CSS_SELECTOR, ".captcha-grid .cell, .bls-grid img")
        )
    )

    for idx in ordered_indices:
        if isinstance(idx, int) and idx < len(cells):
            cells[idx].click()
            time.sleep(0.5)  # Ordering needs pauses between clicks


def inject_hidden_response(driver, solution_value):
    """Set the solution in a hidden input field."""
    driver.execute_script("""
        var inputs = document.querySelectorAll(
            'input[name*="captcha"], input[name*="response"], #captcha-answer'
        );
        for (var i = 0; i < inputs.length; i++) {
            inputs[i].value = arguments[0];
        }
    """, str(solution_value))

التدفق الكامل لحل شبكة BLS من البداية للنهاية

تجمع الدالة التالية الخطوات في مسار واحد: انتظار الشبكة، قراءة النص الإرشادي، الحل عبر CaptchaAI، ثم اختيار طريقة الحقن تلقائياً:

# full_flow.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


def handle_bls_grid(driver, pageurl):
    """Complete BLS grid CAPTCHA handling."""

    wait = WebDriverWait(driver, 15)

    # Wait for CAPTCHA to load
    captcha = wait.until(
        EC.presence_of_element_located(
            (By.CSS_SELECTOR, "[data-sitekey], .bls-captcha")
        )
    )
    sitekey = captcha.get_attribute("data-sitekey")

    # Get instructions
    instructions = None
    try:
        inst = driver.find_element(By.CSS_SELECTOR, ".captcha-instructions")
        instructions = inst.text.strip()
    except Exception:
        pass

    # Solve via CaptchaAI
    solution = solve_bls_grid(sitekey, pageurl, instructions)
    parsed = parse_grid_response(solution)

    # Determine response method
    grid_cells = driver.find_elements(
        By.CSS_SELECTOR, ".captcha-grid .cell, .bls-grid img"
    )

    if grid_cells:
        # Click-based response
        if isinstance(parsed, list) and all(isinstance(x, int) for x in parsed):
            click_grid_cells(driver, parsed)
        else:
            inject_hidden_response(driver, solution)
    else:
        # Hidden input response
        inject_hidden_response(driver, solution)

    # Submit
    submit = driver.find_element(
        By.CSS_SELECTOR, "button[type='submit'], .submit-btn, #verify"
    )
    submit.click()

    return True

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

معظم الإخفاقات ليست في الحل بل في طريقة إرساله. يربط الجدول كل عرض شائع بسببه والإجراء المناسب:

المشكلة السبب المرجّح الإجراء
النقر على خلايا خاطئة عدم تطابق محدد خلية الشبكة افحص شبكة HTML وحدّث محددات CSS
رفض الطلب نقر سريع أكثر من اللازم أضف تأخيراً بين 300 و500 مللي ثانية بين النقرات
عدم تطابق تنسيق الحل الموقع يتوقع قناعاً نقطياً وأرسلت مؤشرات استخدم format_for_submission() للتحويل
الشبكة غير محمّلة بالكامل تحميل الصور بطيء انتظر اكتمال تحميل كل صور الشبكة قبل الحل

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

ما الفرق بين قائمة المؤشرات والقناع النقطي في الاستجابة؟

قائمة المؤشرات تعدّد الخلايا المختارة فقط، بينما القناع النقطي يمثّل الشبكة كاملة بخانة لكل خلية. تحقق من التنسيق الذي يتوقعه الموقع، وحوّل بينهما عبر format_for_submission().

لماذا يُرفض الحل رغم أن الصور المختارة صحيحة؟

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

هل يمكن إعادة استخدام حل شبكة BLS في طلب لاحق؟

لا. كل حل مرتبط بجلسة تحدٍّ محددة، فاحصل على حل جديد لكل محاولة.

ماذا يحدث إذا تغيّرت الشبكة بعد الإرسال؟

تعرض بعض نماذج BLS تحدياً ثانياً بعد اجتياز الأول. تحقق من ظهور عنصر CAPTCHA جديد بعد الإرسال، ثم كرّر مسار الحل نفسه.

ما دور معامل instructions في نتيجة الحل؟

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


أدلة ذات صلة


عالج تحديات شبكة BLS بثبات — ابدأ الآن مع CaptchaAI.

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