Integrations

Undetected ChromeDriver dengan Integrasi CaptchaAI

Skrip Selenium Anda tetap akan bertemu CAPTCHA, bahkan setelah memakai undetected-chromedriver. Pustaka itu menurunkan frekuensi tantangan, bukan menghapusnya — dan sisanya perlu diselesaikan lewat API. Jawaban praktisnya: pakai undetected-chromedriver untuk sesi browser yang bersih, lalu kirim CAPTCHA yang tetap muncul ke CaptchaAI dan suntikkan token yang dikembalikan ke form.

Empat langkah di bawah ini adalah pola yang sama untuk semua tipe CAPTCHA, dan sisa artikel hanya menerjemahkannya ke konteks Selenium:

  1. Ambil sitekey dari halaman yang sedang dibuka driver.
  2. Kirim task ke in.php beserta pageurl, lalu simpan task ID-nya.
  3. Polling res.php sampai token siap.
  4. Suntikkan token ke field yang benar dan picu callback halaman.

Contoh kodenya memakai Python dengan reCAPTCHA v2 dan Cloudflare Turnstile — dua tipe yang paling sering ditemui tim otomatisasi di Indonesia.

Kenapa dua lapisan ini dipasangkan

Pola dua lapis paling terasa manfaatnya pada pekerjaan yang berulang setiap hari, bukan pada eksperimen sekali jalan:

  • Monitoring harga harian untuk klien agensi, dijalankan terjadwal dari instance di AWS ap-southeast-3 (Jakarta) atau ap-southeast-1 (Singapura).
  • Regression test terhadap form checkout dan login milik sendiri, di lingkungan staging.
  • Job pengumpulan data terjadwal milik tim data startup, yang harus selesai sebelum jam kerja dimulai.

Ketiganya punya ciri sama: CAPTCHA hanya muncul pada sebagian kecil eksekusi. Anda tidak butuh solver di setiap iterasi, Anda butuh solver yang siap ketika tantangan benar-benar muncul.

Di situlah model harga berbasis thread relevan untuk pasar kontrak lokal yang sangat sensitif terhadap biaya. CaptchaAI menagih per thread bersamaan, bukan per solve, dengan solve tanpa batas per thread selama periode langganan. Paket BASIC ($15/bulan, 5 thread) cukup untuk satu atau dua worker Selenium sekuensial; STANDARD ($30/bulan, 15 thread) memberi ruang untuk beberapa job paralel. Biaya bulanan tetap sama entah skrip memicu 50 atau 5.000 CAPTCHA — penting untuk pekerjaan berbayar tetap yang tidak bisa menyerap tagihan variabel.

Satu catatan kepatuhan: ambil hanya data yang memang boleh Anda proses, dan hindari data pribadi. UU Pelindungan Data Pribadi (UU 27/2022) berlaku juga untuk hasil scraping, bukan hanya untuk data yang Anda kumpulkan lewat form.

Yang perlu disiapkan sebelum menjalankan kode

Persyaratan Detail
API key CaptchaAI captchaai.com
Python 3.8+
Browser Chrome Terpasang di sistem Anda

Instal dependensi:

pip install undetected-chromedriver requests

Kalau Anda belum pernah memanggil endpoint CaptchaAI sama sekali, pahami dulu bentuk request dan format responsnya — polanya sama persis di semua bahasa pemrograman.

Konfigurasi driver Selenium

import undetected_chromedriver as uc
import requests
import time


def create_stealth_browser():
    """Create an undetected Chrome browser instance."""
    options = uc.ChromeOptions()
    options.add_argument("--no-sandbox")
    options.add_argument("--window-size=1920,1080")

    driver = uc.Chrome(options=options)
    return driver

uc.Chrome() mengurus pencocokan versi driver dengan Chrome yang terpasang, jadi Anda tidak perlu mengunduh binary secara manual. Di server tanpa GUI, tambahkan --disable-dev-shm-usage supaya Chrome tidak kehabisan shared memory di dalam container — kasus yang sering muncul di VPS kecil dengan /dev/shm bawaan 64 MB.

Menyelesaikan reCAPTCHA v2 di sesi Selenium

Langkah 1: buka halaman dan ambil sitekey

API_KEY = "YOUR_API_KEY"


def extract_recaptcha_sitekey(driver):
    """Extract reCAPTCHA v2 sitekey from the page."""
    try:
        element = driver.find_element("css selector", "[data-sitekey]")
        return element.get_attribute("data-sitekey")
    except Exception:
        # Try finding in iframe src
        iframes = driver.find_elements("css selector", "iframe[src*='recaptcha']")
        for iframe in iframes:
            src = iframe.get_attribute("src")
            if "k=" in src:
                return src.split("k=")[1].split("&")[0]
    return None

Atribut data-sitekey adalah jalur paling langsung. Kalau widget baru dirender belakangan oleh JavaScript, fallback ke src iframe reCAPTCHA dan ambil nilai parameter k=. Beri jeda WebDriverWait sebelum pencarian ini pada halaman yang berat.

Langkah 2: kirim task ke CaptchaAI

def solve_recaptcha_v2(sitekey, pageurl):
    """Submit reCAPTCHA v2 to CaptchaAI and return the token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]

    time.sleep(20)
    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()

        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)

    raise TimeoutError("Solve timed out")

Jeda 20 detik sebelum polling pertama itu disengaja: menanyakan hasil lebih awal hanya menghasilkan CAPCHA_NOT_READY berulang kali dan membuang request. Setelah itu, polling tiap 5 detik sudah cukup rapat. Rincian parameter per tipe ada di panduan reCAPTCHA v2 lewat API.

Langkah 3: suntik token dan picu callback

def inject_recaptcha_token(driver, token):
    """Inject the solved token into the page and submit."""
    driver.execute_script(f'''
        document.getElementById("g-recaptcha-response").innerHTML = "{token}";
        document.getElementById("g-recaptcha-response").style.display = "block";
    ''')

    # If there's a callback function, trigger it
    driver.execute_script(f'''
        if (typeof ___grecaptcha_cfg !== 'undefined') {{
            var clients = ___grecaptcha_cfg.clients;
            for (var key in clients) {{
                var client = clients[key];
                if (client && client.callback) {{
                    client.callback("{token}");
                }}
            }}
        }}
    ''')

Mengisi g-recaptcha-response saja sering tidak cukup. Banyak halaman baru mengaktifkan tombol submit setelah callback reCAPTCHA dipanggil, jadi blok kedua bukan tambahan opsional — itu penyebab paling umum ketika token sudah valid tetapi form tetap menolak.

Contoh utuh: alur login dari nol sampai submit

import undetected_chromedriver as uc
import requests
import time

API_KEY = "YOUR_API_KEY"


def solve_recaptcha(sitekey, pageurl):
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY, "method": "userrecaptcha",
        "googlekey": sitekey, "pageurl": pageurl, "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    time.sleep(20)

    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")


def main():
    driver = uc.Chrome()

    try:
        # Navigate to target page
        driver.get("https://staging.example.com/qa-login")
        time.sleep(3)

        # Fill in form fields
        driver.find_element("id", "username").send_keys("user")
        driver.find_element("id", "password").send_keys("pass")

        # Extract sitekey
        element = driver.find_element("css selector", "[data-sitekey]")
        sitekey = element.get_attribute("data-sitekey")
        pageurl = driver.current_url
        print(f"Sitekey: {sitekey}")

        # Solve CAPTCHA
        token = solve_recaptcha(sitekey, pageurl)
        print(f"Token: {token[:50]}...")

        # Inject token
        driver.execute_script(
            f'document.getElementById("g-recaptcha-response").innerHTML = "{token}";'
        )

        # Submit form
        driver.find_element("id", "submit-btn").click()
        time.sleep(3)

        print(f"Current URL: {driver.current_url}")
    finally:
        driver.quit()


if __name__ == "__main__":
    main()

Perhatikan blok finally: driver.quit() wajib dipanggil. Skrip terjadwal yang gagal di tengah jalan tanpa menutup driver akan meninggalkan proses Chrome menumpuk di server sampai memori habis — masalah operasional yang jauh lebih sering merusak job daripada CAPTCHA itu sendiri.

Sebelum mengarahkan skrip ini ke sistem produksi Anda, jalankan dulu terhadap halaman staging milik sendiri. Alamat staging.example.com/qa-login pada contoh di atas ada untuk alasan itu.

Ketika target memakai Cloudflare Turnstile

Alur untuk widget Cloudflare Turnstile identik; yang berubah hanya method dan nama field token:

def solve_turnstile(sitekey, pageurl):
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY, "method": "turnstile",
        "sitekey": sitekey, "pageurl": pageurl, "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    time.sleep(10)

    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")


# Inject Turnstile token
def inject_turnstile_token(driver, token):
    driver.execute_script(f'''
        var input = document.querySelector('[name="cf-turnstile-response"]');
        if (input) input.value = "{token}";
    ''')

Tiga perbedaan yang perlu diingat:

  • Parameternya bernama sitekey, bukan googlekey.
  • Token masuk ke input cf-turnstile-response, bukan g-recaptcha-response.
  • Jeda awal cukup 10 detik karena Turnstile umumnya selesai lebih cepat.

Penjelasan lengkapnya ada di panduan Cloudflare Turnstile lewat API. Kalau target Anda memakai GeeTest v3, metode geetest mengikuti pola kirim-polling-suntik yang persis sama, hanya dengan set parameter yang berbeda.

Ketika skrip gagal: gejala dan penyebabnya

Gejala Sebab Perbaikan
Versi Chrome tidak cocok UC tidak menemukan driver yang sesuai Perbarui Chrome atau tentukan version_main pada uc.Chrome()
CAPTCHA tetap muncul Situs memeriksa sinyal browser tingkat lanjut Wajar — biarkan CaptchaAI yang menyelesaikannya
Injeksi token gagal ID elemen atau callback tidak sesuai Periksa implementasi reCAPTCHA pada halaman tersebut
WebDriverException Proses Chrome berhenti mendadak Tambahkan --no-sandbox dan --disable-dev-shm-usage
Polling selalu CAPCHA_NOT_READY Batas waktu terlalu pendek atau pageurl salah Perbanyak iterasi; pastikan pageurl sama persis dengan URL halaman

Dua baris terakhir menyumbang sebagian besar pertanyaan yang masuk. Nilai pageurl harus URL halaman tempat widget dirender, bukan URL endpoint form-nya — perbedaan yang mudah terlewat ketika form dikirim ke path lain.

Pertanyaan umum

Berapa lama waktu penyelesaian reCAPTCHA v2 lewat CaptchaAI?

Umumnya beberapa puluh detik. Karena itu skrip di atas menunggu 20 detik sebelum polling pertama, lalu memeriksa tiap 5 detik hingga 30 kali. Turnstile biasanya lebih cepat, sehingga jeda awalnya cukup 10 detik.

Berapa thread yang saya butuhkan untuk satu skrip Selenium?

Satu instance Selenium yang berjalan sekuensial hanya memakai satu thread pada satu waktu, jadi BASIC ($15/bulan, 5 thread) sudah longgar. Naikkan ke STANDARD ($30/bulan, 15 thread) begitu Anda menjalankan beberapa worker paralel, misalnya satu proses per klien.

Bisakah pola ini dijalankan di Selenium Grid atau di dalam Docker?

Bisa, tetapi undetected-chromedriver menambal biner driver secara lokal. Untuk setup terdistribusi, siapkan driver yang sudah dipatch di setiap node atau di dalam image, jangan mengandalkan patching saat runtime pada container yang read-only.

hCaptcha dan FunCaptcha: kenapa tidak ada di contoh?

Karena keduanya memang tidak didukung CaptchaAI saat ini, begitu pula GeeTest v4 yang statusnya masih segera hadir. Yang tersedia adalah reCAPTCHA v2 dan v3 beserta varian Enterprise, Cloudflare Turnstile dan Cloudflare Challenge, GeeTest v3, serta CAPTCHA gambar dan grid — ditambah CaptchaFox (beta), Friendly Captcha (beta), dan Lemin (beta). Rencanakan pendekatan lain sejak awal kalau target Anda memakai tipe yang belum tersedia.

Apakah mode headless mengubah kebutuhan solver saya?

Mode headless cenderung memicu lebih banyak tantangan, jadi alokasikan thread sedikit lebih besar daripada saat menjalankan Chrome dengan jendela. Gunakan options.add_argument("--headless=new") untuk generasi headless terbaru Chrome.

Langkah berikutnya

Daftar di captchaai.com, salin API key ke API_KEY, lalu jalankan skrip login di atas terhadap halaman staging milik Anda sendiri. Setelah satu token berhasil disuntikkan, sisanya hanya soal menyesuaikan selector.

Panduan terkait

Komentar dinonaktifkan untuk artikel ini.