Tutorial

Pemuatan CAPTCHA Dinamis: Deteksi CAPTCHA Lazy-Loaded

Tidak semua CAPTCHA muncul saat halaman pertama kali dimuat. Banyak situs me-render CAPTCHA secara lazy — setelah klik tombol, fokus form, scroll, atau timer. Jika otomatisasi Anda langsung mengambil source halaman, CAPTCHA belum ada di sana. Panduan ini mencakup cara mendeteksi dan menunggu CAPTCHA yang dimuat secara dinamis.


Trigger Lazy-Load yang Umum

Trigger Contoh Cara mengaktifkan
Klik tombol "Submit" menambahkan reCAPTCHA ke form Klik tombol terlebih dahulu
Form focus CAPTCHA muncul saat input difokuskan Fokuskan field email/password
Posisi scroll CAPTCHA di-load saat section terlihat Scroll ke form
Timer CAPTCHA di-load setelah 3 detik Tunggu delay-nya
Kondisi JavaScript CAPTCHA di-load setelah response AJAX Trigger request prasyarat

Metode 1: MutationObserver

Perhatikan DOM untuk elemen CAPTCHA yang ditambahkan:

Puppeteer

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://staging.example.com/qa-login');

// Set up MutationObserver before triggering the CAPTCHA
const captchaInfo = await page.evaluate(() => {
  return new Promise((resolve) => {
    // Check if already present
    const existing = document.querySelector('.g-recaptcha, .cf-turnstile, .h-captcha');
    if (existing) {
      resolve({
        type: existing.className,
        sitekey: existing.getAttribute('data-sitekey'),
      });
      return;
    }

    // Watch for new elements
    const observer = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        for (const node of mutation.addedNodes) {
          if (node.nodeType !== 1) continue;

          const captcha = node.matches?.('.g-recaptcha, .cf-turnstile, .h-captcha')
            ? node
            : node.querySelector?.('.g-recaptcha, .cf-turnstile, .h-captcha');

          if (captcha) {
            observer.disconnect();
            resolve({
              type: captcha.className,
              sitekey: captcha.getAttribute('data-sitekey'),
            });
            return;
          }
        }
      }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // Timeout after 30 seconds
    setTimeout(() => {
      observer.disconnect();
      resolve(null);
    }, 30000);
  });
});

console.log('Detected CAPTCHA:', captchaInfo);

Trigger load

// Klik tombol submit untuk trigger CAPTCHA
await page.click('#submit-btn');

// Atau fokuskan input
await page.focus('#email');

// Atau scroll ke form
await page.evaluate(() => {
  document.querySelector('#signup-form').scrollIntoView();
});

Metode 2: Tunggu Injeksi Script

CAPTCHA membutuhkan library JavaScript mereka. Pantau saat library tersebut di-load:

// Tunggu script reCAPTCHA selesai di-load
await page.waitForFunction(() => {
  return typeof window.grecaptcha !== 'undefined' 
    && typeof window.grecaptcha.render === 'function';
}, { timeout: 30000 });

// Sekarang ekstrak parameter
const sitekey = await page.evaluate(() => {
  const el = document.querySelector('.g-recaptcha');
  return el?.getAttribute('data-sitekey');
});

Untuk Turnstile

await page.waitForFunction(() => {
  return typeof window.turnstile !== 'undefined';
}, { timeout: 30000 });

const sitekey = await page.evaluate(() => {
  const el = document.querySelector('.cf-turnstile');
  return el?.getAttribute('data-sitekey');
});

Metode 3: Intercept Render Call

Hook ke library CAPTCHA sebelum di-render:

// Inject before page scripts run
await page.evaluateOnNewDocument(() => {
  window.__captchaDetected = null;

  // Hook grecaptcha.render
  let _grecaptcha;
  Object.defineProperty(window, 'grecaptcha', {
    set(val) {
      _grecaptcha = val;
      const origRender = val.render;
      val.render = function(container, params) {
        window.__captchaDetected = {
          type: 'recaptcha',
          sitekey: params.sitekey,
          callback: params.callback?.name,
          container: typeof container === 'string' ? container : container.id,
        };
        return origRender.apply(this, arguments);
      };
    },
    get() { return _grecaptcha; },
  });
});

await page.goto('https://example.com/signup');

// Trigger the CAPTCHA (click, scroll, etc.)
await page.click('#show-form');

// Wait for detection
await page.waitForFunction(() => window.__captchaDetected !== null, {
  timeout: 30000,
});

const detected = await page.evaluate(() => window.__captchaDetected);
console.log('Detected:', detected);
// { type: 'recaptcha', sitekey: '6Le-wvkS...', callback: 'onCaptcha', container: 'recaptcha-box' }

Python (Selenium): Menunggu CAPTCHA Lazy-Loaded

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

driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-login")

# Trigger the CAPTCHA loading
submit = driver.find_element(By.ID, "submit-btn")
submit.click()

# Wait for CAPTCHA to appear
try:
    captcha_el = WebDriverWait(driver, 30).until(
        EC.presence_of_element_located((
            By.CSS_SELECTOR,
            ".g-recaptcha, .cf-turnstile, .h-captcha"
        ))
    )
    sitekey = captcha_el.get_attribute("data-sitekey")
    captcha_class = captcha_el.get_attribute("class")

    if "g-recaptcha" in captcha_class:
        captcha_type = "recaptcha"
    elif "cf-turnstile" in captcha_class:
        captcha_type = "turnstile"
    else:
        captcha_type = "hcaptcha"

    print(f"Type: {captcha_type}, Sitekey: {sitekey}")
except Exception:
    print("No CAPTCHA appeared within 30 seconds")

Tunggu iframe (reCAPTCHA)

# reCAPTCHA me-load iframe bahkan ketika div ada tapi script masih loading
WebDriverWait(driver, 30).until(
    EC.presence_of_element_located((
        By.CSS_SELECTOR,
        "iframe[src*='recaptcha'], iframe[src*='challenges.cloudflare.com']"
    ))
)
print("CAPTCHA iframe loaded")

Flow Lengkap: Deteksi + Solve

import requests
import time

def detect_and_solve(driver, api_key, trigger_action=None):
    """Detect a lazy-loaded CAPTCHA, solve it, and inject the token."""

    # 1. Trigger the CAPTCHA
    if trigger_action:
        trigger_action(driver)

    # 2. Wait for it to appear
    captcha_el = WebDriverWait(driver, 30).until(
        EC.presence_of_element_located((
            By.CSS_SELECTOR,
            ".g-recaptcha, .cf-turnstile, .h-captcha"
        ))
    )

    sitekey = captcha_el.get_attribute("data-sitekey")
    page_url = driver.current_url
    captcha_class = captcha_el.get_attribute("class")

    # 3. Determine type and method
    if "g-recaptcha" in captcha_class:
        method, key_param, token_field = "userrecaptcha", "googlekey", "g-recaptcha-response"
    elif "cf-turnstile" in captcha_class:
        method, key_param, token_field = "turnstile", "sitekey", "cf-turnstile-response"
    else:
        method, key_param, token_field = "hcaptcha", "sitekey", "h-captcha-response"

    # 4. Solve with CaptchaAI
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key, "method": method,
        key_param: sitekey, "pageurl": page_url, "json": "1",
    }).json()

    task_id = resp["request"]
    for _ in range(24):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get", "id": task_id, "json": "1"
        }).json()
        if result["status"] == 1:
            token = result["request"]
            break

    # 5. Inject
    driver.execute_script(f"""
        const el = document.querySelector('textarea[name="{token_field}"], input[name="{token_field}"]');
        if (el) el.value = arguments[0];
    """, token)

    return token

Pemecahan Masalah

Masalah Penyebab Perbaikan
CAPTCHA tidak pernah muncul Trigger action salah Periksa halaman untuk menemukan apa yang memicu CAPTCHA
Sitekey adalah null Elemen ada tapi script belum berjalan Tunggu iframe CAPTCHA, bukan hanya div-nya
Observer tidak mendeteksinya CAPTCHA sudah ada sebelumnya Periksa elemen yang sudah ada sebelum setup observer
Timeout CAPTCHA hanya di-load untuk pengguna nyata Gunakan browser penuh dengan sinyal browser yang realistis

Pertanyaan Umum

Bagaimana saya tahu apakah CAPTCHA di-load secara lazy?

Lihat source halaman (Ctrl+U). Jika div atau script CAPTCHA tidak ada tapi muncul saat Anda berinteraksi dengan halaman, berarti CAPTCHA tersebut lazy-loaded.

Apakah ini berfungsi di browser headless?

Ya, dengan catatan. Beberapa situs hanya me-load CAPTCHA untuk browser non-headless. Gunakan headless: 'new' di Puppeteer atau puppeteer-extra (mode standar).


Solve CAPTCHA Apa Pun dengan CaptchaAI

Dapatkan API key Anda di captchaai.com.


Panduan terkait

Komentar dinonaktifkan untuk artikel ini.