دروس API

معلمات GeeTest Slide CAPTCHA: من الاستخراج إلى الحل عبر CaptchaAI

حلّ تحدي GeeTest v3 المنزلق يعتمد في جوهره على ثلاث معلمات فقط: gt وchallenge وعنوان الصفحة pageurl. إذا استخرجت هذه القيم بشكل صحيح وأرسلتها إلى CaptchaAI قبل أن تنتهي صلاحية التحدي، تحصل في المقابل على ثلاث قيم جاهزة — challenge وvalidate وseccode — تعيدها إلى الموقع المستهدف لإتمام التحقق. في هذا الدليل نفكّك كل معلمة على حدة، ثم نسير في مسار عملي كامل بلغة Python من لحظة الاستخراج حتى الاستجابة النهائية للموقع.


معلمات GeeTest v3 الأساسية

قبل بناء أي طلب، عليك التمييز بين المعلمات التي يقبلها إرسال GeeTest v3 وأيّها إلزامي فعلاً:

المعلمة مطلوبة الوصف
gt نعم معرّف حساب GeeTest الخاص بالموقع (سلسلة سداسية عشرية من 32 حرفًا). يظهر في مصدر الصفحة أو في استجابة واجهة برمجة التطبيقات
challenge نعم سلسلة التحدي الخاصة بالجلسة. يجب أن تكون جديدة مع كل عملية حل
pageurl نعم عنوان URL الكامل للصفحة التي يظهر فيها اختبار CAPTCHA
api_server لا النطاق الفرعي المخصص لخادم GeeTest API عند استخدامه

المعلمتان gt وchallenge هما محور كل شيء: الأولى ثابتة لكل موقع، والثانية متغيّرة لكل جلسة. الخلط بينهما أو إرسال challenge قديم هو السبب الأول لفشل الحل.


كيف يعمل تحدي التمرير في GeeTest؟

يعرض GeeTest v3 قطعة أحجية (puzzle) يسحبها المستخدم أفقيًا إلى مكانها الصحيح. خلف هذه الحركة البسيطة توجد آلية تحقق من ثلاث مراحل: الموقع يُعرّف نفسه عبر حساب gt ثابت، ثم يطلب من خادم GeeTest سلسلة challenge جديدة لكل زيارة، وبعد اكتمال السحب يعيد الخادم قيمتَي validate وseccode اللتين تثبتان أن التفاعل صحيح.

المشكلة العملية أمام مهندس استخراج البيانات أن قيمة challenge ترتبط بجلسة زمنية قصيرة، ومسار الأحجية يتطلب حسابات دقيقة. بدلاً من محاكاة الحركة يدويًا، ترسل هذه القيم إلى CaptchaAI التي تعيد لك الحل جاهزًا للإرسال. GeeTest v3 مدعوم بشكل كامل في CaptchaAI، بينما لا يزال دعم GeeTest v4 قيد الإطلاق ولم يتوفر بعد.


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

الخطوة الأولى دائمًا هي قراءة الصفحة والبحث عن gt ثم عن نقطة النهاية التي تُرجع challenge. في كثير من المواقع تجد gt مضمّنًا مباشرة في مصدر HTML، بينما يأتي challenge من طلب تسجيل منفصل مثل register-slide. الكود التالي يجرّب المسارين معًا:

# extract_geetest_params.py
import requests
import re
import json


def extract_geetest_v3(page_url, session=None):
    """Extract GeeTest v3 gt and challenge from a page."""
    if session is None:
        session = requests.Session()
        session.headers["User-Agent"] = (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36"
        )

    resp = session.get(page_url, timeout=15)
    html = resp.text

    # Method 1: Extract gt from HTML
    gt_match = re.search(r'gt["\']?\s*[:=]\s*["\']([a-f0-9]{32})', html)
    gt = gt_match.group(1) if gt_match else None

    # Method 2: Find API endpoint that returns challenge
    api_match = re.search(r'(https?://[^"\']+register-slide[^"\']*)', html)

    challenge = None
    if api_match:
        api_url = api_match.group(1)
        api_resp = session.get(api_url, timeout=10)
        try:
            data = api_resp.json()
            challenge = data.get("challenge")
            gt = gt or data.get("gt")
        except json.JSONDecodeError:
            pass

    if not challenge:
        # Try embedded challenge
        ch_match = re.search(r'challenge["\']?\s*[:=]\s*["\']([a-f0-9]+)', html)
        challenge = ch_match.group(1) if ch_match else None

    return {"gt": gt, "challenge": challenge, "pageurl": page_url}


# Usage
params = extract_geetest_v3("https://example.com/login")
print(f"gt: {params['gt']}")
print(f"challenge: {params['challenge']}")

إذا كان gt يُحمَّل عبر JavaScript ولم يظهر في مصدر الصفحة، افتح طلبات الشبكة (XHR) وابحث عن استجابة نقطة التسجيل، أو استعن بأداة مثل Selenium لتشغيل الصفحة بالكامل.


الخطوة 2: إرسال المعلمات إلى CaptchaAI

بعد الحصول على gt وchallenge، ترسلهما مع pageurl إلى نقطة النهاية in.php مستخدمًا method=geetest. تُعيد الخدمة معرّف مهمة، ثم تستطلع النتيجة من res.php حتى يجهز الحل. عادةً ما يكتمل حل GeeTest v3 خلال 10 إلى 20 ثانية:

# solve_geetest.py
import requests
import time
import os


def solve_geetest(gt, challenge, pageurl, api_server=None):
    """Solve GeeTest v3 slide CAPTCHA via CaptchaAI."""
    api_key = os.environ["CAPTCHAAI_API_KEY"]

    payload = {
        "key": api_key,
        "method": "geetest",
        "gt": gt,
        "challenge": challenge,
        "pageurl": pageurl,
        "json": 1,
    }

    if api_server:
        payload["api_server"] = api_server

    # Submit
    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 — GeeTest typically solves in 10-20 seconds
    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"]  # Returns challenge, validate, seccode
        if data["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(data["request"])
        time.sleep(5)

    raise TimeoutError("GeeTest solve timeout")

لاحظ أن الاستجابة الناجحة تحمل القيم الثلاث المطلوبة: challenge وvalidate وseccode. هذه هي البيانات التي سيعتمد عليها الموقع لقبول الجلسة.


الخطوة 3: إعادة الحل إلى الموقع المستهدف

الحل الذي تعيده CaptchaAI ليس النهاية؛ عليك تمرير قيمه الثلاث إلى نقطة نهاية التحقق في الموقع نفسه، غالبًا عبر حقول geetest_challenge وgeetest_validate وgeetest_seccode:

# submit_solution.py
import json


def submit_geetest_solution(session, validation_url, solution, original_challenge):
    """Submit GeeTest solution to the target site."""
    # Parse solution if string
    if isinstance(solution, str):
        solution = json.loads(solution)

    payload = {
        "geetest_challenge": solution.get("challenge", original_challenge),
        "geetest_validate": solution.get("validate", ""),
        "geetest_seccode": solution.get("seccode", ""),
    }

    resp = session.post(validation_url, data=payload, timeout=30)
    return resp


# Complete flow
def full_geetest_flow(page_url, validation_url):
    import requests
    from extract_geetest_params import extract_geetest_v3

    session = requests.Session()
    session.headers["User-Agent"] = (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36"
    )

    # Step 1: Extract parameters
    params = extract_geetest_v3(page_url, session)
    print(f"gt: {params['gt']}, challenge: {params['challenge'][:16]}...")

    # Step 2: Solve
    solution = solve_geetest(
        params["gt"], params["challenge"], params["pageurl"],
    )
    print("Solved!")

    # Step 3: Submit
    resp = submit_geetest_solution(
        session, validation_url, solution, params["challenge"],
    )
    print(f"Validation response: {resp.status_code}")
    return resp

من المهم استخدام الجلسة (session) نفسها في الاستخراج والإرسال، حتى تبقى ملفات تعريف الارتباط ورؤوس الطلب متطابقة مع الجلسة التي وُلّد فيها challenge.


الحفاظ على نضارة قيمة challenge

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

# fresh_challenge.py
import time


def get_fresh_challenge(session, register_url):
    """Always fetch a fresh challenge before solving."""
    resp = session.get(register_url, timeout=10)
    data = resp.json()

    challenge = data.get("challenge")
    if not challenge:
        raise ValueError("No challenge returned")

    return challenge


def solve_with_fresh_challenge(session, gt, register_url, pageurl):
    """Ensure challenge is fresh before submitting to CaptchaAI."""
    challenge = get_fresh_challenge(session, register_url)

    # Submit immediately — don't let it expire
    solution = solve_geetest(gt, challenge, pageurl)
    return solution

القاعدة الذهبية: استخرج challenge وأرسله إلى CaptchaAI خلال ثوانٍ. أي تحدٍ قديم أو منتهي الصلاحية سيفشل حتمًا مهما كانت بقية المعلمات صحيحة.


التعامل مع خادم GeeTest مخصص

بعض المواقع لا تستخدم النطاق الافتراضي api.geetest.com، بل نطاقًا فرعيًا خاصًا بمنطقتها. في هذه الحالة مرّر المعلمة api_server لتوجيه الطلب إلى الخادم الصحيح:

# The api_server parameter specifies a custom GeeTest backend
# Default: api.geetest.com
# Custom examples: api-na.geetest.com, api.geetest.com/ajax-custom

solution = solve_geetest(
    gt="abc123...",
    challenge="def456...",
    pageurl="https://example.com/login",
    api_server="api-na.geetest.com",  # North America endpoint
)

لمعرفة القيمة الصحيحة، راقب طلبات الشبكة في الصفحة وابحث عن نطاق بالشكل api-*.geetest.com.


سيناريو عملي: أتمتة موقع حجوزات إقليمي

تخيّل مهندسًا في القاهرة أو الرياض يبني أداة مراقبة للأسعار على موقع حجوزات أو متجر إلكتروني إقليمي يحمي صفحة تسجيل الدخول بـ GeeTest v3. مع كل تشغيل للأداة، تستخرج السكربت قيمة gt الثابتة وchallenge الجديد، ثم ترسلهما إلى CaptchaAI وتعيد الحل إلى الموقع لإكمال الجلسة والوصول إلى لوحة النتائج.

لأن CaptchaAI تعتمد التسعير على أساس عدد الـ Threads المتزامنة لا على كل عملية حل، يستطيع هذا المهندس البدء بخطة BASIC ($15 شهريًا، 5 threads) لأحمال الاختبار الخفيفة، والانتقال إلى ADVANCE ($90 شهريًا، 50 thread) عندما يحتاج إلى تشغيل عشرات الجلسات المتوازية أثناء جمع البيانات في ساعات الذروة. لا توجد رسوم إضافية لكل تحدٍ ولا سقف يومي داخل الخطة، ما يجعل التكلفة قابلة للتنبؤ عند التوسّع.


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

المشكلة السبب المحتمل الإجراء
ERROR_CAPTCHA_UNSOLVABLE قيمة challenge منتهية أو معرّف gt خاطئ اجلب challenge جديدًا مباشرة قبل الإرسال وتأكد من صحة gt
validate فارغة معلمات موجّهة لموقع GeeTest v4 (غير مدعوم بعد) تأكد أن الموقع يعتمد GeeTest v3؛ دعم v4 قيد الإطلاق
رفض الموقع للحل نقص إحدى القيم الثلاث أرسل geetest_challenge وgeetest_validate وgeetest_seccode كاملة
تعذّر إيجاد gt القيمة مُحمَّلة عبر JavaScript استخدم Selenium أو راجع استجابات XHR لنقطة التسجيل

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

هل يمكن حلّ GeeTest v4 عبر CaptchaAI؟

ليس بعد. الإصدار المتاح للحل هو GeeTest v3 فقط، أما GeeTest v4 فهو قيد الإطلاق ولم يصبح متاحًا حتى الآن. هذا الدليل مخصّص لـ GeeTest v3 المنزلق.

لماذا يتكرر خطأ ERROR_CAPTCHA_UNSOLVABLE؟

السبب الأكثر شيوعًا هو إرسال قيمة challenge قديمة انتهت صلاحيتها قبل وصول الطلب. اجلب التحدي جديدًا وأرسله فورًا، وتأكد أيضًا من أن gt يخصّ الموقع نفسه وأن pageurl صحيح.

هل أحتاج متصفحًا كاملاً مثل Selenium لاستخراج المعلمات؟

ليس دائمًا. إذا ظهرت gt وchallenge في مصدر HTML أو في استجابة طلب تسجيل بسيط، تكفي مكتبة requests. تلجأ إلى Selenium فقط عندما تُحمَّل القيم ديناميكيًا عبر JavaScript.

كم يستغرق حل تحدي GeeTest v3 تقريبًا؟

يكتمل الحل عادةً خلال 10 إلى 20 ثانية. لذلك يبدأ الكود بانتظار 10 ثوانٍ ثم يستطلع النتيجة من res.php على فترات قصيرة حتى تجهز.

أي خطة CaptchaAI تناسب حجم طلبات GeeTest لديّ؟

يعتمد الاختيار على عدد الجلسات المتزامنة. تكفي BASIC ($15 شهريًا، 5 threads) للاختبارات الخفيفة، بينما تناسب ADVANCE ($90 شهريًا، 50 thread) أحمال جمع البيانات الأكبر، مع عدد حلول غير محدود داخل كل thread.


أدلة ذات صلة


أتقن معلمات GeeTest وابدأ الحل عبر CaptchaAI.

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