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

reCAPTCHA في تطبيقات الصفحة الواحدة: أنماط التحميل الديناميكية

تقوم تطبيقات الصفحة الواحدة بتحميل reCAPTCHA ديناميكيًا - الأداة غير موجودة في HTML الأولي. يعرض نموذج تسجيل الدخول React اختبار CAPTCHA فقط عند تحميل المكون. تقوم صفحة Vue checkout بتحميل reCAPTCHA بعد أن ينقر المستخدم على "وضع الطلب". يفتقد استخراج مصدر الصفحة التقليدي هذه الأمور تمامًا. فيما يلي كيفية اكتشاف reCAPTCHA المحملة ديناميكيًا وحلها.

لماذا تختلف المنتجعات الصحية؟

صفحة تقليدية سبا
البرنامج النصي reCAPTCHA بتنسيق HTML الأولي تم إدخال البرنامج النصي بعد تغيير المسار
يتم عرض القطعة عند تحميل الصفحة يتم عرض القطعة على جبل المكون
مفتاح الموقع في مصدر الصفحة مفتاح الموقع في حزمة JavaScript
يتم إرسال النموذج عبر POST يتم إرسال النموذج عبر XHR/fetch

في SPA، قد لا تكون أداة reCAPTCHA موجودة حتى يقوم المستخدم بتشغيلها. يجب أن تنتظر الأتمتة الخاصة بك حتى تظهر الأداة.

اكتشاف أداة reCAPTCHA

انتظر العنصر

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://example.com/login")

    # SPA may need a click or navigation to trigger reCAPTCHA
    page.click("#show-login-form")

    # Wait for reCAPTCHA iframe to appear
    recaptcha_frame = page.wait_for_selector(
        "iframe[src*='recaptcha']",
        timeout=15000
    )
    print("reCAPTCHA detected:", recaptcha_frame.get_attribute("src"))

استخراج مفتاح الموقع

يمكن أن يكون مفتاح الموقع في مواقع متعددة في SPA:

# Method 1: From the iframe src
iframe_src = recaptcha_frame.get_attribute("src")
# src contains: ...?k=6LcR_RsTAAAAADge...
import re
match = re.search(r'[?&]k=([^&]+)', iframe_src)
site_key = match.group(1) if match else None

# Method 2: From data-sitekey attribute
site_key = page.eval_on_selector(
    "[data-sitekey]",
    "el => el.getAttribute('data-sitekey')"
)

# Method 3: From JavaScript bundle (last resort)
site_key = page.evaluate("""
    () => {
        // Check for grecaptcha render calls
        const scripts = document.querySelectorAll('script');
        for (const s of scripts) {
            const match = s.textContent.match(/sitekey['":\s]+(['"])(6L[^'"]+)\\1/);
            if (match) return match[2];
        }
        return null;
    }
""")

حل اختبار reCAPTCHA

بمجرد حصولك على مفتاح الموقع، قم بإرساله إلى CaptchaAI:

import requests
import time

def solve_recaptcha(site_key, page_url):
    # Submit task
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    # Poll for result
    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]
    raise TimeoutError("Solve timed out")

حقن الرمز المميز في SPA

المنتجعات الصحية لا تقدم النماذج التقليدية. تحتاج إلى إدخال الرمز المميز حيث يتوقعه التطبيق.

الطريقة الأولى: تعيين منطقة النص المخفية

token = solve_recaptcha(site_key, "https://example.com/login")

# Inject into the g-recaptcha-response textarea
page.evaluate(f"""
    document.getElementById('g-recaptcha-response').value = '{token}';
""")

# Submit the form
page.click("#login-button")

الطريقة الثانية: تشغيل رد الاتصال

تستخدم العديد من تطبيقات SPA reCAPTCHA وظيفة رد الاتصال:

# Find the callback function name
callback = page.evaluate("""
    () => {
        const widget = document.querySelector('.g-recaptcha');
        return widget?.getAttribute('data-callback') || null;
    }
""")

# Call it with the token
if callback:
    page.evaluate(f"window['{callback}']('{token}')")
else:
    # Try the default grecaptcha callback
    page.evaluate(f"""
        if (window.grecaptcha) {{
            // Set the response and trigger verification
            document.getElementById('g-recaptcha-response').value = '{token}';
            // Find and call any registered callbacks
            const form = document.querySelector('form');
            if (form) form.dispatchEvent(new Event('submit'));
        }}
    """)

الطريقة الثالثة: اعتراض XHR (JavaScript / Puppeteer)

const puppeteer = require('puppeteer');

async function solveRecaptchaInSPA() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();

  // Intercept the API call and inject the token
  await page.setRequestInterception(true);
  page.on('request', request => {
    if (request.url().includes('/api/login')) {
      const postData = JSON.parse(request.postData() || '{}');
      // Token already set via page.evaluate — let it pass
      request.continue();
    } else {
      request.continue();
    }
  });

  await page.goto('https://example.com/login');
  await page.waitForSelector('[data-sitekey]');

  const siteKey = await page.$eval(
    '[data-sitekey]',
    el => el.getAttribute('data-sitekey')
  );

  // Solve with CaptchaAI (implementation omitted — same as Python)
  const token = await solveCaptcha(siteKey, page.url());

  // Inject token and trigger callback
  await page.evaluate((t) => {
    document.getElementById('g-recaptcha-response').value = t;
    const callback = document.querySelector('.g-recaptcha')
      ?.getAttribute('data-callback');
    if (callback && window[callback]) {
      window[callback](t);
    }
  }, token);
}

الأنماط الخاصة بالإطار

رد الفعل (رد فعل-جوجل-recaptcha)

غالبًا ما تستخدم تطبيقات React الحزمة react-google-recaptcha. يعرض المكون بشكل غير متزامن:

# Wait for React to mount the component
page.wait_for_selector(".g-recaptcha", state="attached")

# The sitekey is in the rendered div's data attribute
site_key = page.eval_on_selector(
    ".g-recaptcha", "el => el.dataset.sitekey"
)

فيو (vue-recaptcha)

# Vue may use v-if to conditionally render
# Navigate or interact to trigger the condition
page.click("#proceed-to-checkout")
page.wait_for_selector("iframe[src*='recaptcha']")

الزاوي

# Angular apps may lazy-load reCAPTCHA modules
# Wait for the specific Angular component
page.wait_for_selector("re-captcha, app-recaptcha, [data-sitekey]")

التعامل مع تغييرات المسار

تقوم SPA بإعادة استخدام الصفحة - ويتم التنقل دون عمليات إعادة التحميل الكاملة:

# Listen for reCAPTCHA appearing after SPA navigation
page.goto("https://example.com")

# Navigate within the SPA
page.click("a[href='/login']")

# The URL changed but no page reload happened
# Wait for the CAPTCHA to render in the new "page"
page.wait_for_selector("iframe[src*='recaptcha']", timeout=10000)

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

المشكلة السبب الإجراء
يُنشأ الرمز المميز لكن الجهة المستهدفة ترفضه مفتاح الموقع أو الصفحة أو سياق الجلسة لا يتطابق التقط المعلمات من جديد وأعد استخدام الرمز داخل جلسة HTTP أو المتصفح نفسها
تنتهي عملية الاستطلاع بمهلة الفاصل الزمني أو وقت الانتظار أو معالجة الأخطاء صارمة أكثر من اللازم استطلع كل 5 إلى 10 ثوانٍ وافصل بين انتهاء المهلة والأخطاء الفعلية وسجّل السبب
ينجح المثال محليًا لكنه يفشل داخل سير العمل رد النداء أو حقل النموذج أو حقن الرمز مفقود في السلسلة الفعلية تحقق من المسار الكامل بين أداة الحل والطلب النهائي إلى الموقع المستهدف

الخطوات التالية

أدلة ذات صلة

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