Tutoriais

Extração de Iframe CAPTCHA: Resolvendo CAPTCHAs em quadros aninhados

Os CAPTCHAs são frequentemente incorporados em um ou mais iframes. O widget CAPTCHA pode estar dentro de um iframe de pagamento, que por sua vez está dentro de um iframe modal. Para resolver esses CAPTCHAs, você precisa navegar na árvore iframe, extrair a chave do site, resolver via CaptchaAI e injetar o token de volta no contexto correto do quadro.


Como funcionam os iframe CAPTCHAs

Uma estrutura aninhada típica:

Main page
  └── iframe#payment-frame (cross-origin)
        └── iframe[src*="recaptcha/api2/anchor"] (Google-hosted)
              └── reCAPTCHA widget

A chave do site reside no iframe externo (aquele que renderiza o widget). O iframe mais interno do Google é o desafio visual - você não interage diretamente com ele. O atributo data-sitekey ou o parâmetro k= no iframe src é o que você precisa.


Python: troca de 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")

Resultado esperado:

Sitekey: 6Le-SITEKEY-abc123
Page URL: https://example.com/checkout
Token: 03AGdBq26ZfPxL...
Token injected, switched back to main frame

JavaScript: manipulação de quadros do titereiro

O Puppeteer possui suporte de quadro de primeira classe - não é necessária nenhuma troca 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');
})();

Iframes profundamente aninhados

Para três ou mais níveis de aninhamento, encadeie os interruptores de quadro:

Selênio

# 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

Erros comuns

Erro O que acontece Correção
Usando o URL da página principal como pageurl Token rejeitado pelo site Use a URL do quadro que renderiza o widget CAPTCHA
Não voltando para o quadro pai As ações subsequentes falham Ligue para switch_to.parent_frame() ou switch_to.default_content() após a injeção
Extraindo sitekey de iframe errado ERROR_WRONG_GOOGLEKEY A chave do site está no iframe que contém .g-recaptcha, não no iframe de desafio interno do Google
JS de bloqueio de iframe de origem cruzada SecurityError no console Você não pode execute_script dentro de um iframe de origem cruzada; em vez disso, extraia a chave do site do atributo src

Perguntas frequentes

O iframe é de origem cruzada. Ainda posso extrair a chave do site?

Sim. A chave do site está no atributo src ou no atributo data-sitekey do elemento iframe, que pode ser lido no quadro pai. Você nunca precisa executar JavaScript dentro do iframe de origem cruzada.

Devo usar o URL da página pai ou o URL do iframe para pageurl?

Use o URL da página que carrega o widget reCAPTCHA. Normalmente, esse é o URL do próprio iframe, não a página de nível superior. Verifique a configuração do reCAPTCHA do site para confirmar.

Como posso saber em qual quadro injetar o token?

Injete o token no quadro que contém o elemento textarea[name="g-recaptcha-response"] — este é sempre o quadro que renderizou a div .g-recaptcha.


Resolva CAPTCHAs em qualquer profundidade de iframe com CaptchaAI

Obtenha sua chave API emcaptchaai.com.


Guias relacionados

Os comentários estão desativados para este artigo.