Các ứng dụng trang đơn tải reCAPTCHA một cách linh hoạt — tiện ích không tồn tại trong HTML ban đầu. Biểu mẫu đăng nhập React chỉ hiển thị CAPTCHA khi thành phần được gắn kết. Trang thanh toán Vue tải reCAPTCHA sau khi người dùng nhấp vào "Đặt hàng". Việc quét nguồn trang truyền thống hoàn toàn bỏ qua những điều này. Dưới đây là cách phát hiện và giải quyết các reCAPTCHA được tải động.
Tại sao các SPA lại khác nhau
| Trang truyền thống | SPA |
|---|---|
| tập lệnh reCAPTCHA trong HTML ban đầu | Tập lệnh được chèn sau khi thay đổi tuyến đường |
| Widget hiển thị khi tải trang | Widget hiển thị trên thành phần gắn kết |
| Khóa trang web trong nguồn trang | Khóa trang web trong gói JavaScript |
| Biểu mẫu gửi qua POST | Biểu mẫu gửi qua XHR/fetch |
Trong SPA, tiện ích reCAPTCHA có thể không tồn tại cho đến khi một hành động cụ thể của người dùng kích hoạt tiện ích đó. Tự động hóa của bạn phải đợi tiện ích xuất hiện.
Phát hiện tiện ích reCAPTCHA
Chờ đợi phần tử
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"))
Trích xuất khóa trang web
Khóa trang có thể ở nhiều vị trí trong 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;
}
""")
Giải quyết reCAPTCHA
Khi bạn có khóa trang web, hãy gửi tới 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")
Tiêm mã thông báo vào SPA
SPA không gửi các hình thức truyền thống. Bạn cần đưa mã thông báo vào nơi ứng dụng mong đợi.
Phương pháp 1: Đặt vùng văn bản ẩn
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")
Phương pháp 2: Kích hoạt gọi lại
Nhiều triển khai SPA reCAPTCHA sử dụng chức năng gọi lại:
# 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'));
}}
""")
Cách 3: Chặn 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);
}
Các mẫu dành riêng cho khung
Phản ứng (Reac-google-recaptcha)
Các ứng dụng React thường sử dụng gói react-google-recaptcha. Thành phần hiển thị không đồng bộ:
# 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']")
Góc cạnh
# Angular apps may lazy-load reCAPTCHA modules
# Wait for the specific Angular component
page.wait_for_selector("re-captcha, app-recaptcha, [data-sitekey]")
Xử lý thay đổi tuyến đường
SPA sử dụng lại trang - điều hướng diễn ra mà không cần tải lại đầy đủ:
# 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)
Khắc phục sự cố
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
Không tìm thấy vùng văn bản g-recaptcha-response |
SPA chưa hiển thị tiện ích này | Sử dụng wait_for_selector với thời gian chờ thích hợp |
| Mã thông báo đã được chèn nhưng biểu mẫu không gửi được | Cuộc gọi lại không được kích hoạt | Tìm và gọi hàm data-callback |
| Khóa trang web không có trong nguồn trang | Được gói trong JS hoặc được tải động | Đợi kết xuất widget, sau đó trích xuất từ iframe src |
| Mã thông báo hoạt động một lần rồi thất bại | Thành phần hiển thị lại SPA, xóa mã thông báo | Tiêm mã thông báo ngay trước khi gửi biểu mẫu |
| Tiện ích hiển thị lại sau khi chèn mã thông báo | Phản ứng React/Vue xóa giá trị | Sử dụng phương pháp data-callback thay vì đặt vùng văn bản |
Câu hỏi thường gặp
Tôi có thể bỏ qua trình duyệt và giải quyết SPA reCAPTCHA chỉ bằng yêu cầu HTTP không?
Nếu bạn có thể trích xuất khóa trang web và sao chép lệnh gọi API gửi biểu mẫu thì có. Nhiều biểu mẫu SPA gửi qua điểm cuối API REST - bạn có thể gọi nó trực tiếp bằng mã thông báo. Nhưng trước tiên bạn cần có trình duyệt để khám phá khóa trang web và điểm cuối API.
Làm cách nào để xử lý reCAPTCHA chỉ xuất hiện trên một số hành động nhất định của người dùng?
Tự động hóa hành động kích hoạt (nhấp vào nút, điền vào biểu mẫu, điều hướng đến một tuyến đường), sau đó đợi phần tử reCAPTCHA xuất hiện. Sử dụng wait_for_selector với thời gian chờ hợp lý.
CaptchaAI có quan tâm liệu reCAPTCHA có trong SPA không?
Không. CaptchaAI chỉ cần khóa trang và URL trang. Cách tải tiện ích trên trang không ảnh hưởng đến việc giải quyết.
bài viết liên quan
- Cách giải quyết cuộc gọi lại Recaptcha V2 bằng Api
- Xử lý cửa quay Recaptcha V2 trên cùng một trang web
- Cơ chế gọi lại Recaptcha V2
Các bước tiếp theo
Giải quyết các reCAPTCHA được tải động trong bất kỳ SPA nào —lấy khóa API CaptchaAI của bạn.