Tutorial

reCAPTCHA di Single Page Application: Pola Dynamic Loading

Aplikasi satu halaman memuat reCAPTCHA secara dinamis - widget tidak ada dalam HTML awal. Formulir login React merender CAPTCHA hanya ketika komponen dipasang. Halaman checkout Vue memuat reCAPTCHA setelah pengguna mengklik "Pesan." Scraping sumber halaman tradisional tidak memuat semua hal ini. Berikut cara mendeteksi dan menyelesaikan reCAPTCHA yang dimuat secara dinamis.

Mengapa SPA Berbeda

Halaman tradisional SPA
skrip reCAPTCHA dalam HTML awal Skrip disuntikkan setelah perubahan rute
Widget dirender saat memuat halaman Widget dirender pada pemasangan komponen
Kunci situs di sumber halaman Kunci situs dalam paket JavaScript
Formulir dikirimkan melalui POST Formulir dikirimkan melalui XHR/fetch

Di SPA, widget reCAPTCHA mungkin tidak ada sampai tindakan pengguna tertentu memicunya. Otomatisasi Anda harus menunggu widget muncul.

Mendeteksi Widget reCAPTCHA

Tunggu Elemennya

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://staging.example.com/qa-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"))

Ekstrak Sitekey

Kunci situs bisa berada di beberapa lokasi di 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;
    }
""")

Memecahkan reCAPTCHA

Setelah Anda memiliki sitekey, kirimkan ke 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")

Menyuntikkan Token di SPA

SPA tidak mengirimkan formulir tradisional. Anda perlu memasukkan token di tempat yang diharapkan oleh aplikasi.

Metode 1: Atur Area Teks Tersembunyi

token = solve_recaptcha(site_key, "https://staging.example.com/qa-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")

Metode 2: Memicu Callback

Banyak implementasi SPA reCAPTCHA menggunakan fungsi callback:

# 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'));
        }}
    """)

Metode 3: Mencegat 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://staging.example.com/qa-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);
}

Pola Khusus Kerangka

Bereaksi (reaksi-google-recaptcha)

Aplikasi React sering kali menggunakan paket react-google-recaptcha. Komponen dirender secara asinkron:

# 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 (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']")

sudut

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

Menangani Perubahan Rute

SPA menggunakan kembali halaman tersebut — navigasi terjadi tanpa memuat ulang sepenuhnya:

# 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)

Pemecahan Masalah

Masalah Penyebab Solusi
Area teks g-recaptcha-response tidak ditemukan SPA belum merender widgetnya Gunakan wait_for_selector dengan timeout yang memadai
Token disuntikkan tetapi formulir tidak dikirimkan Callback tidak terpicu Temukan dan panggil fungsi data-callback
Kunci situs tidak ada di sumber halaman Dibundel dalam JS atau dimuat secara dinamis Tunggu render widget, lalu ekstrak dari iframe src
Token berfungsi sekali kemudian gagal SPA merender ulang komponen, menghapus token Suntikkan token segera sebelum pengiriman formulir
Widget dirender ulang setelah pengaturan token Reaktivitas React/Vue menghapus nilainya Gunakan pendekatan data-callback alih-alih mengatur textarea

Pertanyaan Umum

Bisakah saya melewati browser dan menyelesaikan reCAPTCHA SPA hanya dengan permintaan HTTP?

Jika Anda dapat mengekstrak sitekey dan mereplikasi panggilan API pengiriman formulir, ya. Banyak formulir SPA dikirimkan melalui endpoint REST API - Anda dapat memanggilnya langsung dengan token. Namun Anda memerlukan browser untuk menemukan sitekey dan endpoint API terlebih dahulu.

Bagaimana cara menangani reCAPTCHA yang hanya muncul pada tindakan pengguna tertentu?

Otomatiskan tindakan pemicuan (klik tombol, isi formulir, navigasikan ke rute), lalu tunggu hingga elemen reCAPTCHA muncul. Gunakan wait_for_selector dengan timeout yang wajar.

Apakah CaptchaAI peduli apakah reCAPTCHA ada di SPA?

Tidak. CaptchaAI hanya memerlukan sitekey dan URL halaman. Cara widget dimuat di halaman tidak memengaruhi solve.

Artikel Terkait

  • Cara Mengatasi Callback Recaptcha V2 Menggunakan Api
  • Penanganan Situs yang Sama Turnstile Recaptcha V2
  • Mekanisme Callback Recaptcha V2

Langkah Selanjutnya

Selesaikan reCAPTCHA yang dimuat secara dinamis di SPA mana pun —dapatkan kunci API CaptchaAI Anda.

Komentar dinonaktifkan untuk artikel ini.