دروس API

معلمات BLS CAPTCHA: دليل instructions وcode مع CaptchaAI

لحلّ اختبار BLS CAPTCHA عبر CaptchaAI تحتاج إلى ثلاث معلمات إلزامية فقط: method بقيمة bls، ثم sitekey وpageurl. أما المعلمتان اللتان تصنعان الفرق في الدقة فهما اختياريتان: instructions التي تنقل نص التحدي، وcode التي تحدّد نوع تحدي BLS المستخدم على الصفحة.

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


جدول مرجعي لمعلمات BLS CAPTCHA

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

المعلمة إلزامية النوع الوصف
method نعم نص يجب أن تساوي bls
sitekey نعم نص مفتاح BLS CAPTCHA الخاص بالموقع
pageurl نعم نص عنوان URL للصفحة التي يظهر عليها التحدي
instructions لا نص نص التعليمات المستخرَج من صورة التحدي
code لا نص معرّف نوع/متغيّر تحدي BLS
json لا عدد صحيح اضبطها على 1 للحصول على استجابة JSON

القاعدة العملية: أرسل الثلاثة الإلزامية دائمًا، وأضف instructions وcode فقط عندما يكون التحدي غامضًا أو متعدّد الأنماط. الإفراط في تمرير قيم غير دقيقة قد يضرّ بالدقة بدل أن يحسّنها.


الخطوة 1: استخراج معلمات BLS من الصفحة

تُحمَّل كثير من تطبيقات BLS ديناميكيًا، لذا لا تكتفِ بقراءة مصدر HTML الأولي. الأفضل فتح الصفحة بمتصفح مؤتمت عبر Selenium، والانتظار حتى يظهر عنصر التحدي، ثم قراءة data-sitekey ونص التعليمات إن وُجد، والبحث عن الكود داخل الحقول المخفية أو السكربتات.

الدالة التالية تجمع هذه الخطوات في مكان واحد وتعيد قاموسًا جاهزًا للإرسال:

# extract_bls.py
import re
from selenium import webdriver
from selenium.webdriver.common.by import By


def extract_bls_params(url):
    """Extract BLS CAPTCHA parameters from a page."""
    driver = webdriver.Chrome()
    driver.get(url)

    params = {"pageurl": url}

    # Extract sitekey
    captcha_el = driver.find_element(By.CSS_SELECTOR, "[data-sitekey], .bls-captcha")
    sitekey = captcha_el.get_attribute("data-sitekey")
    if sitekey:
        params["sitekey"] = sitekey

    # Extract instructions if visible
    try:
        instructions_el = driver.find_element(
            By.CSS_SELECTOR, ".captcha-instructions, .captcha-text"
        )
        params["instructions"] = instructions_el.text.strip()
    except Exception:
        pass

    # Extract code from hidden input or script
    page_source = driver.page_source
    code_match = re.search(r'captcha_code["\']?\s*[:=]\s*["\']([^"\']+)', page_source)
    if code_match:
        params["code"] = code_match.group(1)

    driver.quit()
    return params


# Usage
params = extract_bls_params("https://bls-example.com/appointment")
print(params)

لاحظ أن استخراج sitekey وpageurl وحده يكفي لإرسال أغلب التحديات؛ أما instructions وcode فيُلتقطان انتهازيًا: إن ظهرا استفدنا منهما، وإن غابا أرسلنا الطلب بدونهما بلا خطأ.


الخطوة 2: إرسال التحدي إلى CaptchaAI واستطلاع النتيجة

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

الإرسال الأساسي

# solve_bls_basic.py
import requests
import time
import os


def solve_bls(sitekey, pageurl, instructions=None, code=None):
    """Solve BLS CAPTCHA via CaptchaAI API."""
    api_key = os.environ["CAPTCHAAI_API_KEY"]

    payload = {
        "key": api_key,
        "method": "bls",
        "sitekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }

    # Add optional parameters for higher accuracy
    if instructions:
        payload["instructions"] = instructions
    if code:
        payload["code"] = code

    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"]

    # Poll for result
    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 solve timeout")


# Usage
solution = solve_bls(
    sitekey="your-bls-sitekey",
    pageurl="https://bls-example.com/appointment",
    instructions="Select images in the correct order",
)
print(f"Solution: {solution}")

تُضاف instructions وcode إلى حمولة الطلب فقط عند توفّرهما، وهو نمط جيد يُبقي الطلب نظيفًا. الرسالة CAPCHA_NOT_READY ليست خطأً بل إشارة إلى أن الحل ما يزال قيد المعالجة، فتابع الاستطلاع؛ وأي قيمة أخرى غير المتوقّعة تعني خطأً حقيقيًا يجب إيقاف المحاولة عنده.


معلمة instructions: متى ولماذا تمرّرها

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

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

# Common BLS instruction patterns:
instructions_examples = [
    "Select images in the correct order",
    "Click the images in order from left to right",
    "Arrange the images by number",
    "Select the matching image",
    "Click in the order shown",
]

# Extract instructions from the CAPTCHA image area
def get_instructions_from_page(driver):
    """Try multiple selectors to find instruction text."""
    selectors = [
        ".captcha-instructions",
        ".bls-captcha-text",
        "#captcha-prompt",
        ".challenge-text",
    ]

    for sel in selectors:
        try:
            el = driver.find_element(By.CSS_SELECTOR, sel)
            text = el.text.strip()
            if text:
                return text
        except Exception:
            continue

    return None

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


معلمة code: التعامل مع أنواع تحدي BLS

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

نقطة مهمة كثيرًا ما تُغفَل: قد تتغيّر قيمة code بين الجلسات أو بحسب الموقع الجغرافي للزائر، لذا أعد استخراجها في كل تشغيل بدل تخزينها كقيمة ثابتة. الدالة التالية تبحث عن الكود عبر عدّة أنماط شائعة:

# Detect BLS CAPTCHA code from page
def detect_bls_code(page_source):
    """Detect which BLS CAPTCHA code/type is being used."""
    patterns = [
        (r'captchaType["\']?\s*[:=]\s*["\'](\w+)', "captchaType"),
        (r'data-captcha-code["\']?\s*=\s*["\'](\w+)', "data attribute"),
        (r'bls_code["\']?\s*[:=]\s*["\'](\w+)', "bls_code"),
    ]

    for pattern, source in patterns:
        match = re.search(pattern, page_source)
        if match:
            return match.group(1)

    return None

وإذا أعادت الدالة None فهذا طبيعي غالبًا؛ كثير من مواقع BLS لا تستخدم كودًا صريحًا، فأرسل حينها المعلمات الإلزامية فقط.


الخطوة 3: التدفق الكامل مع Selenium

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

# full_bls_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
import os
import re


def solve_bls_with_selenium(url, form_data=None):
    """Complete BLS CAPTCHA flow using Selenium."""
    driver = webdriver.Chrome()
    driver.get(url)

    wait = WebDriverWait(driver, 15)

    # Fill any form fields before CAPTCHA
    if form_data:
        for field_id, value in form_data.items():
            el = wait.until(EC.presence_of_element_located((By.ID, field_id)))
            el.clear()
            el.send_keys(value)

    # Extract CAPTCHA parameters
    captcha_container = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey], .bls-captcha"))
    )
    sitekey = captcha_container.get_attribute("data-sitekey")

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

    # Solve via API
    solution = solve_bls(
        sitekey=sitekey,
        pageurl=driver.current_url,
        instructions=instructions,
    )

    # Inject solution
    driver.execute_script("""
        var input = document.querySelector('input[name="captcha-response"], #captcha-response');
        if (input) {
            input.value = arguments[0];
        } else {
            var hidden = document.createElement('input');
            hidden.type = 'hidden';
            hidden.name = 'captcha-response';
            hidden.value = arguments[0];
            document.forms[0].appendChild(hidden);
        }
    """, solution)

    # Submit form
    submit_btn = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], #submit")
    submit_btn.click()

    # Wait for confirmation
    wait.until(EC.url_changes(url))
    result_url = driver.current_url
    driver.quit()

    return result_url

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


سيناريو عملي: أتمتة بوابة BLS في المنطقة العربية

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

هنا يظهر أثر ضبط المعلمات: عندما تمرّر instructions الصحيحة يقلّ رفض الحلول، ومع أعباء أكبر يصبح عدد الـ Threads المتاح في خطتك هو ما يحدّد كم تحديًا يمكن حلّه بالتوازي. للمراقبة منخفضة الحجم تكفي خطة BASIC (‏15 دولارًا شهريًا، 5 Threads)؛ ومع تزايد التزامن تنتقل إلى STANDARD (‏30 دولارًا، 15 Thread) أو ADVANCE (‏90 دولارًا، 50 Thread). الأسعار بالدولار الأمريكي، والفوترة قائمة على الـ Threads مع عدد حلول غير محدود لكل Thread خلال الشهر — لا رسوم لكل تحدٍّ ولا سقف يومي.

مسؤوليتك تنحصر في حلّ اختبار CAPTCHA ضمن ما تسمح به شروط استخدام البوابة؛ لا تستخدم الأتمتة لتجاوز قيود لا يحقّ لك تجاوزها.


معالجة الأخطاء الشائعة

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

المشكلة السبب الإجراء
ERROR_BAD_PARAMETERS غياب sitekey أو pageurl تأكّد من استخراج كليهما بشكل صحيح قبل الإرسال
رفض الحل لم تُمرَّر instructions أضف معلمة instructions في التحديات الغامضة
نوع تحدٍّ خاطئ التحدي ليس BLS أصلًا تحقّق مما إذا كان reCAPTCHA أو نوعًا مخصّصًا
sitekey غير موجود تحميل ديناميكي متأخّر انتظر ظهور عنصر التحدي قبل محاولة الاستخراج

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


أسئلة شائعة

ما الفرق بين معلمتَي instructions وcode؟

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

هل تمرير instructions إلزامي دائمًا؟

لا، ليس إلزاميًا. يحلّ CaptchaAI معظم تحديات BLS CAPTCHA دون تمرير instructions، لكن تمريرها يرفع الدقة في التحديات الغامضة التي لا يظهر نصّها داخل الصورة.

هل يستطيع CaptchaAI حل BLS CAPTCHA على بوابات التأشيرات الحكومية؟

نعم، فـ BLS نوع مدعوم رسميًا عبر الطريقة bls، ويُعامَل التحدي بالأسلوب نفسه بصرف النظر عن البوابة التي يظهر عليها. تذكّر أن دورك يقتصر على حلّ اختبار CAPTCHA ضمن استخدام مصرّح به للبوابة.

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

يستغرق الحل عادةً بين 10 و20 ثانية، بمعدّل نجاح مرتفع على نوع BLS المدعوم. صمّم منطق الاستطلاع لديك على مهلة كافية بدل افتراض ردٍّ فوري.

كيف أتأكّد أنّ التحدي هو BLS CAPTCHA فعلًا؟

افحص عنصر التحدي في الصفحة: يحمل BLS عادةً سمة data-sitekey أو فئة CSS مثل .bls-captcha. إذا أشار العنصر إلى reCAPTCHA أو نوع مخصّص آخر، فستحتاج إلى طريقة حلّ مختلفة، وإرسال method: bls عندها سيعيد خطأً.


أدلة ذات صلة


أتقنت الآن معلمتَي instructions وcode؟ ابدأ الحل مع CaptchaAI.

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