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.