Tutorials

Iframe CAPTCHA Çıkarma: İç İçe Çerçevelerdeki CAPTCHA'ları Çözme

Sitekey'i sayfa kaynağından okumaya çalıştığınızda None dönüyorsa ya da gönderdiğiniz token ERROR_WRONG_GOOGLEKEY ile reddediliyorsa, neden neredeyse her zaman aynıdır: CAPTCHA bir iframe'in — çoğu kez iframe içindeki başka bir iframe'in — içinde duruyor ve siz yanlış çerçeve bağlamına bakıyorsunuz. Çözüm dört adımlıdır: çerçeve ağacında doğru iframe'e geçin, sitekey'i çıkarın, CaptchaAI ile çözün ve token'ı widget'ı oluşturan çerçeveye geri enjekte edin. Ödeme sayfaları, 3D Secure akışları ve gömülü giriş formları bu yapıya en sık rastladığınız yerlerdir.


iframe içindeki CAPTCHA neden farklı davranır?

Tarayıcı, her iframe'i ayrı bir belge bağlamı olarak ele alır. driver.find_element veya document.querySelector yalnızca içinde bulunduğunuz çerçevede arama yapar; komşu ya da alt bir iframe'deki öğeleri göremez. Bu yüzden iç içe bir CAPTCHA'da öğe bulma çağrılarınız sessizce boş döner.

Tipik bir iç içe geçmiş yapı şöyledir:

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

Burada iki önemli ayrım var. Birincisi: sitekey, widget'ı oluşturan dış iframe'de (.g-recaptcha div'ini içeren çerçevede) bulunur. En içteki Google iframe'i yalnızca görsel doğrulamayı gösterir; onunla doğrudan etkileşime girmezsiniz. İhtiyacınız olan tek değer, dış iframe öğesinin data-sitekey özelliği veya src içindeki k= parametresidir.

İkincisi: çapraz kökenli (cross-origin) iframe'lerin içine JavaScript enjekte edemezsiniz. Ödeme sağlayıcısının çerçevesi farklı bir alan adından yüklendiğinde, tarayıcının aynı köken politikası execute_script çağrılarını SecurityError ile engeller. Ancak iframe öğesinin src özelliği ana çerçeveden okunabildiği için sitekey'i çıkarmak için o çerçevenin içine girmenize gerek yoktur.


Python: Selenium ile iframe geçişi

Selenium'da her çerçeveye açıkça geçmeniz gerekir. Aşağıdaki akış dış iframe'e geçer, reCAPTCHA iframe'inin src'sinden sitekey'i çıkarır, CaptchaAI'ye gönderir ve token'ı geri enjekte eder.

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")

Beklenen çıktı:

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

Dikkat edilmesi gereken tek nokta, pageurl olarak sürücünün o an içinde bulunduğu çerçevenin URL'sini (driver.current_url) kullanmaktır — üst düzey sayfanın adresini değil. Token'ı enjekte ettikten sonra switch_to.default_content() ile ana çerçeveye dönmeyi unutmayın; aksi halde formu gönderen sonraki adımlar başarısız olur.


JavaScript: Puppeteer ile çerçeve yönetimi

Puppeteer birinci sınıf çerçeve desteğine sahiptir; her seferinde manuel olarak "içeri geçmeniz" gerekmez. contentFrame() size doğrudan bir Frame nesnesi verir ve öğe aramalarını o çerçevede yaparsınız.

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');
})();

Aynı userrecaptcha yöntemi Cloudflare Turnstile için turnstile yöntemine dönüşür; Turnstile'ın token'ı ise cf-turnstile-response alanına yazılır. Çerçeve gezinme mantığı her iki CAPTCHA türü için aynıdır.


Çok derin iç içe iframe'ler

Üç ya da daha fazla yuvalama seviyesi olduğunda çerçeve geçişlerini zincirlersiniz. Her seviyeye sırayla girin, sitekey'i en içteki hedef çerçevede çıkarın, işiniz bitince aynı yoldan geri dönün.

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()

switch_to.parent_frame() sizi yalnızca bir seviye yukarı taşır; switch_to.default_content() ise doğrudan en üste, ana belgeye döndürür. Derin ağaçlarda hangi seviyede olduğunuzu kaybetmemek için geçişleri tek yönde tutun.

Puppeteer

const frame1 = await (await page.$('iframe#iframe-1')).contentFrame();
const frame2 = await (await frame1.$('iframe#iframe-2')).contentFrame();
// Extract sitekey from frame2

Yerel senaryo: Türk e-ticaret ödeme akışını test etmek

Türkiye'deki geliştiricilerin büyük kısmı e-ticaret ve fintech entegrasyonlarında çalışır; iç içe iframe deseni de en çok burada karşınıza çıkar. Tipik bir örnek: kendi staging ortamınızdaki bir sepet sayfasında, ödeme sağlayıcısının 3D Secure iframe'i içinde bir reCAPTCHA v2 doğrulaması yer alır. Ödeme akışını otomatik QA testleriyle uçtan uca doğrulamak isterken bu CAPTCHA testi bloke eder.

Bu durumda yukarıdaki Selenium akışını staging.example.com/qa-checkout gibi kendi test ortamınıza yöneltir, sitekey'i ödeme çerçevesinden çıkarır ve token'ı geri enjekte edersiniz. Kazıdığınız ya da işlediğiniz veride kişisel bilgi varsa, bunun KVKK kapsamına girdiğini ve yalnızca yetkili QA/veri toplama iş akışlarında kullanılması gerektiğini unutmayın.

Ölçek büyüdüğünde tek darboğaz eşzamanlılıktır. CaptchaAI thread tabanlı çalışır: her plan aylık sabit USD fiyatla belirli sayıda eşzamanlı thread verir ve thread başına çözüm sayısı sınırsızdır. Çerçeve ağırlıklı sayfaları paralel test ediyorsanız BASIC ($15/ay, 5 thread) başlangıç için yeterlidir; daha yüksek hacimde ADVANCE ($90/ay, 50 thread) gibi bir plana geçebilirsiniz. TL kuru dalgalanırken öngörülebilir USD fiyatlandırması burada gerçek bir avantajdır.


Sık yapılan hatalar ve çözümleri

Hata Ne olur? Düzeltme
Ana sayfa URL'sini pageurl olarak kullanmak Token site tarafından reddedilir CAPTCHA widget'ını oluşturan çerçevenin URL'sini kullanın
Ana çerçeveye geri dönmemek Sonraki eylemler başarısız olur Enjeksiyondan sonra switch_to.parent_frame() ya da switch_to.default_content() çağırın
Sitekey'i yanlış iframe'den çıkarmak ERROR_WRONG_GOOGLEKEY Sitekey, dahili Google doğrulama iframe'inde değil, .g-recaptcha'yı içeren iframe'dedir
Çapraz kökenli iframe JS'yi engelliyor Konsolda SecurityError Çapraz kökenli iframe içinde execute_script çalıştıramazsınız; sitekey'i src özelliğinden çıkarın

Sık sorulan sorular

ERROR_WRONG_GOOGLEKEY hatasını nasıl düzeltirim?

Bu hata neredeyse her zaman sitekey'i yanlış çerçeveden okuduğunuz anlamına gelir. Sitekey, .g-recaptcha div'ini oluşturan iframe'in src ya da data-sitekey değerindedir — en içteki Google doğrulama iframe'inde değil. Doğru çerçeveye geçip değeri oradan çıkarın.

Çapraz kökenli bir iframe'de sitekey'e nasıl erişirim?

iframe öğesinin src özelliği ana çerçeveden okunabildiği için sitekey'i çıkarmak için o çerçevenin içine girmenize gerek yoktur. execute_script çağrısı SecurityError verse bile, get_attribute("src") çalışmaya devam eder.

CaptchaAI iframe içindeki hCaptcha'yı çözer mi?

Hayır. CaptchaAI hCaptcha'yı desteklemez. iframe içindeki reCAPTCHA v2/v3 ve Cloudflare Turnstile için ise aynı çerçeve gezinme yöntemi geçerlidir.

İç içe iframe'lerde Selenium mü Puppeteer mı daha kolay?

Puppeteer'ın contentFrame() yapısı manuel geçiş gerektirmediği için derin ağaçlarda genellikle daha az koda mal olur. Selenium'da her seviyeye açıkça switch_to.frame ile girmeniz gerekir; ekip zaten Selenium kullanıyorsa bu tamamen yeterlidir.


CaptchaAI ile istediğiniz iframe derinliğinde çözün

API anahtarınızı şu adresten alın: captchaai.com. Anahtarı örnek koda yapıştırdığınız anda, çerçeve derinliğinden bağımsız olarak sitekey çıkarma ve token enjeksiyonu aynı dört adımla çalışır.


İlgili kılavuzlar

Bu makale için yorumlar devre dışı bırakılmıştır.