الدروس التطبيقية

استخراج معلمات reCAPTCHA من مصدر الصفحة

أكثر سبب يجعل مهمة حل reCAPTCHA تفشل عند أي خدمة هو إرسال مفتاح موقع خاطئ أو ناقص المعلمات. قبل أن ترسل أي طلب إلى CaptchaAI تحتاج قيمتين على الأقل: مفتاح الموقع (sitekey) وعنوان الصفحة (pageurl). وبحسب إصدار reCAPTCHA قد تحتاج حتى أربع قيم إضافية — مثل action في الإصدار 3، أو data-s على مواقع Google، أو علامة Enterprise. هذا الدليل يوضّح أين تختبئ كل معلمة داخل مصدر الصفحة، وكيف تستخرجها بأربع طرق عملية باستخدام Python وJavaScript.

الفكرة الأساسية بسيطة: مفتاح الموقع قيمة عامة موجودة في شيفرة الصفحة، لكن موضعها يختلف — أحيانًا في سمة HTML مباشرة، وأحيانًا داخل رابط سكربت، أو ضمن إطار iframe، أو في نداء JavaScript يُنفَّذ وقت التشغيل. لهذا لا توجد طريقة واحدة تكفي كل المواقع، بل مجموعة طرق تجرّبها بالترتيب حتى تعثر على القيمة الصحيحة.


أي معلمات تحتاجها حسب إصدار reCAPTCHA

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

المعلمة reCAPTCHA v2 عادي v2 غير مرئي v3 Enterprise
googlekey (مفتاح الموقع) مطلوب مطلوب مطلوب مطلوب
pageurl مطلوب مطلوب مطلوب مطلوب
invisible 1
action مطلوب في بعض الأحيان
data-s في بعض الأحيان في بعض الأحيان
enterprise 1

مفتاح الموقع وعنوان الصفحة إلزاميان دائمًا. البقية شرطية: invisible للنسخة غير المرئية، وaction أساسي في الإصدار 3 لأنه يؤثر مباشرة في درجة الثقة، وdata-s يظهر غالبًا على صفحات تملكها Google، وعلامة enterprise تُرفع فقط لمفاتيح reCAPTCHA Enterprise.


الطريقة الأولى: استخراج المعلمات من سمات HTML

في أغلب صفحات reCAPTCHA v2 يُوضع مفتاح الموقع داخل سمة data-sitekey على عنصر div يحمل الصنف g-recaptcha. هذه أبسط حالة وأكثرها شيوعًا، وتكفي فيها قراءة مصدر HTML الثابت دون فتح متصفح.

قراءة سمة data-sitekey مباشرة

يبحث المثال التالي عن مفتاح الموقع، ويكشف في الوقت نفسه إن كان الويدجت غير مرئي، ويقرأ اسم دالة callback وقيمة data-s إن وُجدت:

import re
import requests

url = "https://example.com/login"
html = requests.get(url).text

# Find data-sitekey
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', html)
if match:
    sitekey = match.group(1)
    print(f"Sitekey: {sitekey}")

# Check if invisible
invisible_match = re.search(r'data-size=["\']invisible["\']', html)
is_invisible = bool(invisible_match)
print(f"Invisible: {is_invisible}")

# Find callback
callback_match = re.search(r'data-callback=["\'](\w+)["\']', html)
callback = callback_match.group(1) if callback_match else None
print(f"Callback: {callback}")

# Check for data-s (Google-owned sites)
data_s_match = re.search(r'data-s=["\']([^"\']+)["\']', html)
data_s = data_s_match.group(1) if data_s_match else None
print(f"data-s: {data_s}")

استخراج المعلمات عبر Puppeteer

حين تُبنى الصفحة بجافاسكربت ولا يظهر الويدجت في HTML الأولي، استعن بمتصفح بلا واجهة. يفتح المثال التالي الصفحة عبر Puppeteer، ينتظر اكتمال الشبكة، ثم يقرأ السمات مباشرة من DOM بعد اكتمال العرض:

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/login', { waitUntil: 'networkidle2' });

const params = await page.evaluate(() => {
  const widget = document.querySelector('.g-recaptcha');
  if (!widget) return null;

  return {
    sitekey: widget.getAttribute('data-sitekey'),
    size: widget.getAttribute('data-size'),
    callback: widget.getAttribute('data-callback'),
    dataS: widget.getAttribute('data-s'),
    invisible: widget.getAttribute('data-size') === 'invisible',
  };
});

console.log(params);

الطريقة الثانية: استخراج مفتاح الموقع من وسم السكربت

مواقع reCAPTCHA v3 لا تضع مفتاح الموقع في سمة HTML، بل تمرّره داخل رابط السكربت نفسه ضمن المعامل render. النقطة نفسها تنطبق على Enterprise مع اختلاف اسم الملف.

مفاتيح reCAPTCHA v3 وEnterprise داخل رابط السكربت

يستخرج هذا المثال المفتاح من قيمة render في رابط السكربت، ويميّز في الوقت نفسه بين reCAPTCHA العادي وEnterprise عبر اسم الملف enterprise.js:

# Find sitekey from script src
v3_match = re.search(
    r'recaptcha/(?:api|enterprise)\.js\?.*?render=([A-Za-z0-9_-]+)',
    html
)
if v3_match:
    sitekey = v3_match.group(1)
    print(f"v3 Sitekey: {sitekey}")

# Check enterprise
is_enterprise = 'enterprise.js' in html
print(f"Enterprise: {is_enterprise}")

استخراج معلمة action من كود JavaScript

في الإصدار 3 لا تُكتب action في سمة HTML، بل تُمرَّر ضمن نداء grecaptcha.execute داخل كود JavaScript. لذلك تحتاج تعبيرًا نمطيًا يقرأ القيمة من داخل النداء:

# Search for grecaptcha.execute calls
action_match = re.search(
    r'grecaptcha\.execute\s*\([^,]+,\s*\{[^}]*action\s*:\s*["\']([^"\']+)',
    html
)
if action_match:
    action = action_match.group(1)
    print(f"Action: {action}")

إرسال قيمة action مطابقة لما يستخدمه الموقع فعليًا مهم في الإصدار 3، لأن اختلافها قد يخفض درجة الثقة الناتجة عن الحل.


الطريقة الثالثة: استخراج مفتاح الموقع من رابط الـ iframe

أحيانًا لا يظهر مفتاح الموقع في السمات ولا في السكربت، لكنه موجود ضمن رابط إطار الـ iframe الذي يعرض reCAPTCHA. المفتاح يكون في المعامل k داخل رابط api2/anchor:

# Find reCAPTCHA iframe
iframe_match = re.search(
    r'<iframe[^>]+src=["\']([^"\']*recaptcha/api2/anchor[^"\']*)["\']',
    html
)
if iframe_match:
    iframe_src = iframe_match.group(1)
    sitekey_match = re.search(r'k=([A-Za-z0-9_-]+)', iframe_src)
    if sitekey_match:
        sitekey = sitekey_match.group(1)
        print(f"Iframe sitekey: {sitekey}")

الطريقة الرابعة: استخراج المعلمات من العرض الديناميكي عبر grecaptcha.render

بعض الصفحات لا تكتب الويدجت في HTML إطلاقًا، بل تنشئه وقت التشغيل عبر نداء grecaptcha.render() وتمرّر الإعدادات ككائن JavaScript. عندها استخرج مفتاح الموقع وcallback والحجم من داخل هذا الكائن:

# Find grecaptcha.render calls
render_match = re.search(
    r'grecaptcha\.render\s*\([^,]*,\s*\{([^}]+)\}',
    html
)
if render_match:
    config = render_match.group(1)
    sk = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', config)
    cb = re.search(r'callback\s*:\s*["\']?(\w+)', config)
    sz = re.search(r'size\s*:\s*["\'](\w+)', config)
    print(f"Sitekey: {sk.group(1) if sk else 'not found'}")
    print(f"Callback: {cb.group(1) if cb else 'not found'}")
    print(f"Size: {sz.group(1) if sz else 'not found'}")

دالة استخراج جامعة تجمع الطرق الأربع

بدل تشغيل كل طريقة يدويًا، ادمجها في دالة واحدة تجرّب المصادر بالترتيب — من السمة إلى السكربت إلى الـ iframe إلى العرض الديناميكي — وتتوقف عند أول مفتاح تجده، ثم تكمل بكشف الإصدار والمعلمات الشرطية:

import re
import requests

def extract_recaptcha_params(url):
    html = requests.get(url, timeout=15).text
    params = {"pageurl": url}

    # Sitekey from data-sitekey
    sk = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)', html)
    if sk:
        params["sitekey"] = sk.group(1)

    # Sitekey from script render parameter (v3)
    if "sitekey" not in params:
        v3 = re.search(r'render=([A-Za-z0-9_-]{20,})', html)
        if v3:
            params["sitekey"] = v3.group(1)

    # Sitekey from iframe
    if "sitekey" not in params:
        iframe = re.search(r'recaptcha.*?k=([A-Za-z0-9_-]+)', html)
        if iframe:
            params["sitekey"] = iframe.group(1)

    # Sitekey from grecaptcha.render
    if "sitekey" not in params:
        render = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', html)
        if render:
            params["sitekey"] = render.group(1)

    # Version detection
    if re.search(r'data-size=["\']invisible', html):
        params["invisible"] = True
    if 'enterprise.js' in html:
        params["enterprise"] = True

    # Action (v3)
    action = re.search(
        r'action\s*:\s*["\']([^"\']+)',
        html[html.find('grecaptcha.execute'):] if 'grecaptcha.execute' in html else ''
    )
    if action:
        params["action"] = action.group(1)

    # data-s
    ds = re.search(r'data-s=["\']([^"\']+)', html)
    if ds:
        params["data_s"] = ds.group(1)

    # Callback
    cb = re.search(r'data-callback=["\'](\w+)', html)
    if cb:
        params["callback"] = cb.group(1)

    return params

# Usage
params = extract_recaptcha_params("https://example.com/login")
for k, v in params.items():
    print(f"  {k}: {v}")

مع صفحة تسجيل نموذجية بويدجت غير مرئي، يكون الناتج المتوقع على هذا النحو:

  pageurl: https://example.com/login
  sitekey: 6Le-SITEKEY-abc123
  invisible: True
  callback: onCaptchaComplete

إرسال المعلمات المستخرجة إلى CaptchaAI

بعد جمع المعلمات، ابنِ حمولة الطلب واملأ الحقول الشرطية فقط عند وجودها. تُرسل الحمولة إلى نقطة النهاية in.php بالطريقة userrecaptcha التي تخدم كل إصدارات reCAPTCHA — v2 وv3 وEnterprise:

data = {
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": params["sitekey"],
    "pageurl": params["pageurl"],
    "json": "1",
}

if params.get("invisible"):
    data["invisible"] = "1"
if params.get("enterprise"):
    data["enterprise"] = "1"
if params.get("action"):
    data["action"] = params["action"]
if params.get("data_s"):
    data["data-s"] = params["data_s"]

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

بعد الإرسال تستطلع النتيجة من res.php حتى يعود الرمز الجاهز، ثم تحقنه في النموذج تحت الحقل g-recaptcha-response.


مثال تطبيقي: مراقبة صفحة حجز فعالية بإصدار reCAPTCHA v3

تخيّل فريقًا يبني أداة داخلية لمتابعة توافر تذاكر حفل موسيقي على منصة حجز في الرياض. صفحة الحجز تحمي نموذجها بـ reCAPTCHA v3، ويُمرَّر لها action باسم submit_order داخل نداء grecaptcha.execute. لو أرسل الفريق المفتاح وحده دون هذه القيمة، سيُقبل الطلب شكليًا لكن بدرجة ثقة منخفضة قد يرفضها الخادم. بتشغيل الدالة الجامعة أعلاه على مصدر الصفحة، يُلتقط مفتاح الموقع من رابط السكربت وقيمة action من كود JavaScript معًا، فتُبنى حمولة مطابقة لما يرسله المتصفح الحقيقي. هذا النمط نفسه يخدم مراقبة أسعار متاجر التجارة الإلكترونية أو صفحات تسجيل الخدمات الحكومية في المنطقة العربية، حيث ينتشر الإصدار 3 المعتمد على درجة الثقة بدل الاختبار المرئي.


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

عندما لا يظهر مفتاح الموقع أو تأتي القيمة خاطئة، يعود السبب غالبًا إلى إحدى الحالات في الجدول التالي:

المشكلة السبب الحل
لم يُعثر على مفتاح الموقع الصفحة تستخدم العرض الديناميكي استخدم Puppeteer أو Selenium بدل HTML الثابت
مفتاح الموقع خاطئ وجود أكثر من عنصر reCAPTCHA تأكد من الويدجت المرتبط بالنموذج الذي ترسله
لم يُعثر على action مُعرّفة في ملف JS خارجي اجلب ملفات JavaScript المرتبطة وابحث فيها
data-s تتغير كل طلب Google تجدّدها باستمرار استخرج data-s طازجة قبل كل حل

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

كيف أحدد إصدار reCAPTCHA من مصدر الصفحة؟

اقرأ إشارات ثابتة في الشيفرة: وجود data-sitekey مع الصنف g-recaptcha يدل على الإصدار 2، بينما تحميل api.js?render= يشير إلى الإصدار 3، ووجود enterprise.js يعني نسخة Enterprise. أما data-size="invisible" فيكشف النسخة غير المرئية من الإصدار 2.

أين أجد معلمة action الخاصة بـ reCAPTCHA v3؟

action ليست في HTML بل تُمرَّر داخل نداء grecaptcha.execute في كود JavaScript. ابحث عن هذا النداء في مصدر الصفحة أو في ملفات JS المرتبطة، وانسخ القيمة كما هي حرفيًا لأنها تؤثر في درجة الثقة.

لماذا تتغير قيمة data-s في كل طلب؟

على مواقع Google تُولَّد data-s ديناميكيًا وتنتهي صلاحيتها بسرعة، لذلك القيمة القديمة تفشل. استخرج data-s طازجة من الصفحة مباشرة قبل كل عملية حل بدل تخزينها وإعادة استخدامها.

ماذا أفعل عند وجود أكثر من reCAPTCHA في الصفحة نفسها؟

قد تحتوي الصفحة على عدة ويدجتات لنماذج مختلفة. طابِق الويدجت مع النموذج الذي ترسله فعلًا عبر تتبّع الحاوية الأقرب له في DOM، وتجنّب أخذ أول مفتاح تصادفه لأنه قد يخص نموذجًا آخر.


ابدأ بحل reCAPTCHA بالمعلمات التي استخرجتها

بمجرد أن تجمع مفتاح الموقع وبقية المعلمات، تكون جاهزًا لإرسالها والحصول على الرمز المحلول. أنشئ مفتاح الـ API الخاص بك على captchaai.com وابدأ الحل مباشرة.


أدلة ذات صلة

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