CAPTCHA sering tertanam di dalam satu atau lebih iframe. Widget CAPTCHA mungkin ada di dalam iframe pembayaran, yang ada di dalam iframe modal. Untuk solve CAPTCHA ini, Anda perlu menavigasi pohon iframe, ekstrak sitekey, solve via CaptchaAI, dan inject token kembali ke frame context yang benar.
Cara Kerja Iframe CAPTCHA
Struktur bersarang yang khas:
Main page
└── iframe#payment-frame (cross-origin)
└── iframe[src*="recaptcha/api2/anchor"] (Google-hosted)
└── reCAPTCHA widget
Sitekey ada di iframe luar (yang merender widget). Iframe Google paling dalam adalah visual challenge — Anda tidak berinteraksi dengannya secara langsung. Atribut data-sitekey atau parameter k= di src iframe itulah yang Anda butuhkan.
Python: Peralihan iframe selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import requests
import re
import time
API_KEY = "YOUR_API_KEY"
driver = webdriver.Chrome()
driver.get("https://example.com/checkout")
# Step 1: Switch into the outer iframe
wait = WebDriverWait(driver, 15)
outer_iframe = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "iframe#payment-frame"))
)
driver.switch_to.frame(outer_iframe)
# Step 2: Find the reCAPTCHA iframe and extract sitekey
recaptcha_iframe = wait.until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, 'iframe[src*="recaptcha/api2/anchor"]')
)
)
src = recaptcha_iframe.get_attribute("src")
sitekey = re.search(r"k=([A-Za-z0-9_-]+)", src).group(1)
page_url = driver.current_url
print(f"Sitekey: {sitekey}")
print(f"Page URL: {page_url}")
# Step 3: Solve with CaptchaAI
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": "1"
})
task_id = resp.json()["request"]
token = None
for _ in range(24):
time.sleep(5)
poll = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": "1"
}).json()
if poll["status"] == 1:
token = poll["request"]
break
if poll["request"] != "CAPCHA_NOT_READY":
raise Exception(poll["request"])
print(f"Token: {token[:50]}...")
# Step 4: Inject token (still inside the outer iframe)
driver.execute_script("""
document.querySelector('textarea[name="g-recaptcha-response"]').value = arguments[0];
if (typeof grecaptcha !== 'undefined') {
grecaptcha.getResponse = function() { return arguments[0]; };
}
""", token)
# Step 5: Switch back to main page
driver.switch_to.default_content()
print("Token injected, switched back to main frame")
Hasil yang diharapkan:
Sitekey: 6Le-SITEKEY-abc123
Page URL: https://example.com/checkout
Token: 03AGdBq26ZfPxL...
Token injected, switched back to main frame
JavaScript: Penanganan Frame Puppeteer
Puppeteer memiliki dukungan frame kelas satu — tidak perlu switch manual.
const puppeteer = require('puppeteer');
const axios = require('axios');
const API_KEY = 'YOUR_API_KEY';
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/checkout', {
waitUntil: 'networkidle2'
});
// Step 1: Find the payment iframe
const paymentFrameHandle = await page.waitForSelector('iframe#payment-frame');
const paymentFrame = await paymentFrameHandle.contentFrame();
// Step 2: Find reCAPTCHA iframe inside the payment frame
const recaptchaFrameHandle = await paymentFrame.waitForSelector(
'iframe[src*="recaptcha/api2/anchor"]'
);
const src = await paymentFrame.evaluate(
el => el.getAttribute('src'), recaptchaFrameHandle
);
const sitekey = src.match(/k=([A-Za-z0-9_-]+)/)[1];
const pageUrl = page.url();
console.log(`Sitekey: ${sitekey}`);
// Step 3: Solve with CaptchaAI
const submitResp = await axios.post('https://ocr.captchaai.com/in.php', null, {
params: {
key: API_KEY,
method: 'userrecaptcha',
googlekey: sitekey,
pageurl: pageUrl,
json: 1
}
});
const taskId = submitResp.data.request;
let token = null;
for (let i = 0; i < 24; i++) {
await new Promise(r => setTimeout(r, 5000));
const pollResp = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: taskId, json: 1 }
});
if (pollResp.data.status === 1) {
token = pollResp.data.request;
break;
}
if (pollResp.data.request !== 'CAPCHA_NOT_READY') {
throw new Error(pollResp.data.request);
}
}
console.log(`Token: ${token.substring(0, 50)}...`);
// Step 4: Inject token into the payment frame
await paymentFrame.evaluate((tkn) => {
const textarea = document.querySelector(
'textarea[name="g-recaptcha-response"]'
);
textarea.value = tkn;
const callback = document.querySelector('.g-recaptcha')
?.getAttribute('data-callback');
if (callback && typeof window[callback] === 'function') {
window[callback](tkn);
}
}, token);
console.log('Token injected into payment iframe');
})();
Iframe Sangat Bersarang
Untuk tiga atau lebih level bersarang, rangkai frame switch:
Selenium
# Main → iframe-1 → iframe-2 → CAPTCHA
driver.switch_to.frame(driver.find_element(By.ID, "iframe-1"))
driver.switch_to.frame(driver.find_element(By.ID, "iframe-2"))
# Now extract sitekey from this context
# To go back up one level:
driver.switch_to.parent_frame()
# To go back to main:
driver.switch_to.default_content()
Puppeteer
const frame1 = await (await page.$('iframe#iframe-1')).contentFrame();
const frame2 = await (await frame1.$('iframe#iframe-2')).contentFrame();
// Extract sitekey from frame2
Error Umum
| Error | Apa yang terjadi | Solusi |
|---|---|---|
Menggunakan URL halaman utama sebagai pageurl |
Token ditolak oleh situs | Gunakan URL frame yang merender widget CAPTCHA |
| Tidak switch kembali ke parent frame | Aksi selanjutnya gagal | Panggil switch_to.parent_frame() atau switch_to.default_content() setelah inject |
| Mengekstrak sitekey dari iframe yang salah | ERROR_WRONG_GOOGLEKEY |
Sitekey ada di iframe yang berisi .g-recaptcha, bukan iframe Google challenge paling dalam |
| Iframe cross-origin memblokir JS | SecurityError di konsol |
Anda tidak bisa execute_script di dalam iframe cross-origin — ekstrak sitekey dari atribut src |
Pertanyaan Umum
Iframe adalah cross-origin. Apakah saya masih bisa mengekstrak sitekey?
Ya. Sitekey ada dalam atribut src elemen iframe atau atribut data-sitekey, yang bisa dibaca dari parent frame. Anda tidak perlu menjalankan JavaScript di dalam iframe cross-origin.
Haruskah saya menggunakan URL parent atau URL iframe untuk pageurl?
Gunakan URL halaman yang memuat widget reCAPTCHA. Biasanya ini URL iframe, bukan halaman level atas. Cek konfigurasi reCAPTCHA situs untuk konfirmasi.
Bagaimana tahu frame mana tempat inject token?
Inject token ke frame yang berisi elemen textarea[name="g-recaptcha-response"] — ini selalu frame yang merender div .g-recaptcha.
Panduan Terkait
- Menangani Beberapa CAPTCHA dalam Satu Halaman
- Mengekstrak Parameter reCAPTCHA dari Sumber Halaman
- Penanganan CAPTCHA dengan Selenium + Python