Туториалы

Извлечение CAPTCHA из iframe: решение CAPTCHA во вложенных фреймах

CAPTCHA часто встроены в один или несколько iframe. Виджет CAPTCHA может находиться внутри платежного iframe, который сам находится внутри модального iframe. Чтобы решить эти CAPTCHA, вам необходимо перемещаться по дереву iframe, извлечь ключ сайта, решить с помощью CaptchaAI и ввести токен обратно в правильный контекст фрейма.


Как работают iframe CAPTCHA

Типичная вложенная структура:

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

Ключ сайта находится во внешнем iframe (том, который отображает виджет). Самый внутренний iframe Google — это визуальная задача — вы не взаимодействуете с ним напрямую. Атрибут data-sitekey или параметр k= в iframe src — это то, что вам нужно.


Python: переключение 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")

Ожидаемый результат:

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

JavaScript: обработка кадров Puppeteer

Puppeteer имеет первоклассную поддержку кадров — ручное переключение не требуется.

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

Для трех и более уровней вложенности свяжите переключатели фрейма в цепочку:

Селен

# 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

Распространенные ошибки

Ошибка Что происходит Исправить
Использование URL-адреса главной страницы как pageurl Токен отклонен сайтом Используйте URL-адрес фрейма, в котором отображается виджет CAPTCHA.
Не переключаться обратно на родительский фрейм Последующие действия не удались После инъекции позвоните switch_to.parent_frame() или switch_to.default_content().
Извлечение ключа сайта из неправильного iframe ERROR_WRONG_GOOGLEKEY Ключ сайта находится в iframe, содержащем .g-recaptcha, а не во внутреннем iframe вызова Google.
Блокировка iframe в разных источниках JS SecurityError в консоли Вы не можете execute_script внутри iframe с перекрестным происхождением — вместо этого извлеките ключ сайта из атрибута src.

Часто задаваемые вопросы

iframe имеет перекрестное происхождение. Могу ли я извлечь ключ сайта?

Да. Ключ сайта находится в атрибуте src или data-sitekey элемента iframe, который доступен для чтения из родительского фрейма. Вам никогда не понадобится выполнять JavaScript внутри iframe с перекрестным происхождением.

Должен ли я использовать URL-адрес родительской страницы или URL-адрес iframe для pageurl?

Используйте URL-адрес страницы, на которой загружается виджет reCAPTCHA. Обычно это собственный URL-адрес iframe, а не страницы верхнего уровня. Для подтверждения проверьте конфигурацию reCAPTCHA сайта.

Как узнать, в какой кадр вставить токен?

Вставьте токен в кадр, содержащий элемент textarea[name="g-recaptcha-response"] — это всегда кадр, в котором отображается элемент div .g-recaptcha.


Решайте CAPTCHA на любой глубине iframe с помощью CaptchaAI

Получите ключ API по адресуcaptchaai.com.


Связанные руководства

  • Обработка нескольких CAPTCHA на одной странице
  • Извлечение параметров reCAPTCHA из исходного кода страницы
  • Решение CAPTCHA с помощью Selenium + Python
Комментарии для этой статьи отключены.