Jangan menyuruh Selenium menyelesaikan CAPTCHA sendiri. Widget reCAPTCHA maupun Turnstile dirancang agar klik otomatis tidak pernah menghasilkan token yang sah. Pola yang benar memisahkan dua pekerjaan: Selenium memegang sesi, cookie, dan navigasi halaman, sementara penyelesaian CAPTCHA dipindahkan ke API CaptchaAI. Anda membaca sitekey dari DOM, mengirimnya ke API, lalu menyuntikkan token yang kembali ke dalam form sebelum submit.
Di bawah ada skrip Python siap jalan untuk reCAPTCHA v2, varian parameter untuk reCAPTCHA v3 dan Cloudflare Turnstile, hitungan thread untuk sesi paralel, serta daftar kesalahan yang paling sering muncul di tahap injeksi token.
Pola integrasinya: empat titik sentuh dalam satu putaran
- Selenium memuat halaman target
- Skrip Anda membaca sitekey CAPTCHA dari DOM halaman
- CaptchaAI menyelesaikan CAPTCHA berbekal sitekey dan URL halaman
- Skrip Anda menyuntikkan token ke halaman lalu mengirim form
Perhatikan apa yang tidak terjadi di sini: browser tidak pernah menyentuh widget CAPTCHA. Semua penyelesaian berjalan di sisi server CaptchaAI, dan yang kembali ke Selenium hanyalah sebuah string token. Karena itu mode headless berjalan sama baiknya dengan mode berjendela — halaman cukup dimuat sampai atribut data-sitekey tersedia.
Yang tetap harus dijaga adalah waktu: token punya masa berlaku terbatas, jadi rantai kirim task → terima token → suntikkan → submit sebaiknya tidak diselingi langkah lambat.
Yang perlu disiapkan
| Kebutuhan | Detail |
|---|---|
| Python 3.7+ | Dengan pip terpasang |
| Selenium | pip install selenium |
| Chrome + ChromeDriver | Versi yang cocok satu sama lain |
| requests | pip install requests |
| API key CaptchaAI | Dari captchaai.com |
Simpan API key di environment variable, bukan langsung di dalam skrip. Repositori otomatisasi paling sering membocorkan kredensial lewat file contoh yang ikut ter-commit.
Langkah 1: siapkan driver Chrome
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
driver = webdriver.Chrome(options=options)
User agent yang wajar membuat permintaan halaman terlihat seperti Chrome biasa. Jika halaman target Anda rewel terhadap banner otomatisasi bawaan Chrome, dua opsi berikut menutup sebagian besar kasus:
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
Konfigurasi standar ini tidak menggantikan token yang sah; fungsinya hanya menjaga agar halaman memuat komponen CAPTCHA seperti biasa sehingga sitekey muncul di DOM.
Langkah 2: bangun fungsi solver reCAPTCHA v2
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_recaptcha_v2(site_key, page_url):
"""Solve reCAPTCHA v2 using CaptchaAI API."""
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
raise Exception(f"Submit failed: {resp.text}")
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|")[1]
raise Exception(f"Solve failed: {result.text}")
raise TimeoutError("CAPTCHA solve timed out")
Ada tiga hal yang layak diperhatikan di fungsi ini. Pertama, in.php hanya mengembalikan task ID — bukan token — sehingga pengiriman selalu diikuti tahap polling ke res.php. Kedua, respons CAPCHA_NOT_READY bukan kesalahan melainkan status normal: tunggu, jangan kirim ulang task. Ketiga, 60 iterasi dengan jeda 5 detik memberi ruang lapang: reCAPTCHA v2 di CaptchaAI umumnya selesai di bawah 60 detik.
Langkah 3: baca sitekey lalu kirim task
# Navigate to the target page
driver.get("https://staging.example.com/qa-login")
# Wait for the reCAPTCHA to load
wait = WebDriverWait(driver, 10)
recaptcha = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "g-recaptcha"))
)
# Extract the site key
site_key = recaptcha.get_attribute("data-sitekey")
page_url = driver.current_url
print(f"Site key: {site_key}")
print(f"Page URL: {page_url}")
# Solve the CAPTCHA
token = solve_recaptcha_v2(site_key, page_url)
print(f"Token received: {token[:50]}...")
WebDriverWait di sini bukan formalitas. Pada banyak halaman login, container g-recaptcha baru disisipkan setelah bundel JavaScript selesai dieksekusi, dan pencarian elemen yang dijalankan seketika akan gagal dengan NoSuchElementException. Untuk koneksi seluler yang lambat, naikkan batas waktu ke 20 detik.
Pakai driver.current_url sebagai pageurl, bukan URL yang Anda ketik: kalau situs melakukan redirect, URL final itulah yang diverifikasi bersama token.
Langkah 4: suntikkan token dan kirim form
# Inject the token into the reCAPTCHA response field
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').innerHTML = '{token}';
document.getElementById('g-recaptcha-response').style.display = '';
""")
# If the form uses a callback function, trigger it
driver.execute_script(f"""
if (typeof ___grecaptcha_cfg !== 'undefined') {{
Object.keys(___grecaptcha_cfg.clients).forEach(function(key) {{
var client = ___grecaptcha_cfg.clients[key];
if (client.callback) client.callback('{token}');
}});
}}
""")
# Submit the form
driver.find_element(By.CSS_SELECTOR, "form").submit()
# Wait for navigation
wait.until(EC.url_changes(page_url))
print(f"Success! Now on: {driver.current_url}")
Blok pertama mengisi textarea g-recaptcha-response lalu menampilkannya kembali supaya nilainya ikut terkirim bersama form. Blok kedua penting untuk form yang tidak punya tombol submit klasik: banyak implementasi menjalankan callback JavaScript begitu CAPTCHA dinyatakan selesai, dan tanpa memanggil callback itu, form Anda tetap terlihat kosong di mata aplikasi. Kalau setelah submit Anda kembali ke halaman yang sama tanpa pesan kesalahan, callback yang belum terpanggil adalah tersangka pertama.
Skrip lengkap yang bisa langsung dijalankan
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
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 time
API_KEY = "YOUR_API_KEY"
def solve_recaptcha_v2(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
raise Exception(f"Submit failed: {resp.text}")
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|")[1]
raise Exception(f"Solve failed: {result.text}")
raise TimeoutError("Timed out")
def main():
options = Options()
driver = webdriver.Chrome(options=options)
try:
driver.get("https://staging.example.com/qa-login")
wait = WebDriverWait(driver, 10)
# Extract site key
recaptcha = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "g-recaptcha"))
)
site_key = recaptcha.get_attribute("data-sitekey")
# Solve
token = solve_recaptcha_v2(site_key, driver.current_url)
# Inject and submit
driver.execute_script(
f"document.getElementById('g-recaptcha-response').innerHTML = '{token}';"
)
driver.find_element(By.CSS_SELECTOR, "form").submit()
wait.until(EC.url_changes(driver.current_url))
print("Login successful!")
finally:
driver.quit()
if __name__ == "__main__":
main()
Menangani tipe CAPTCHA lain
Kerangka kodenya tidak berubah — yang berbeda hanya parameter yang dikirim ke in.php dan field tujuan tokennya.
reCAPTCHA v3
def solve_recaptcha_v3(site_key, page_url, action="verify"):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"version": "v3",
"action": action
})
task_id = resp.text.split("|")[1]
# ... same polling logic
reCAPTCHA v3 tidak menampilkan widget, jadi tidak ada elemen yang perlu ditunggu. Yang Anda butuhkan adalah sitekey dan nilai action yang dipakai situs; keduanya biasanya terlihat pada skrip yang memanggil grecaptcha.execute. Penyelesaiannya di bawah 4 detik.
Cloudflare Turnstile
def solve_turnstile(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "turnstile",
"sitekey": site_key,
"pageurl": page_url
})
task_id = resp.text.split("|")[1]
# ... same polling logic
Turnstile memakai nama parameter sitekey (bukan googlekey) dan mengembalikan token yang harus masuk ke field cf-turnstile-response, bukan g-recaptcha-response. Salah menaruh token di field tipe lain adalah penyebab klasik form ditolak tanpa penjelasan. Waktu penyelesaian Turnstile di bawah 10 detik.
Berapa thread yang Anda butuhkan untuk sesi paralel
Ini pertanyaan biaya, dan jawabannya berbeda dari model bayar-per-solve. CaptchaAI menagih berdasarkan thread — satu thread berarti satu CAPTCHA yang sedang diproses — dan setiap paket mencakup solve tanpa batas selama bulan berjalan.
Hitungannya jadi sederhana: jumlah thread yang Anda perlukan kira-kira sama dengan jumlah instance Selenium yang menunggu token secara bersamaan, bukan jumlah CAPTCHA per hari. Lima worker paralel di satu VPS sudah terlayani paket BASIC ($15/bulan, 5 thread). Sebuah Selenium Grid berisi 50 container masuk ke ADVANCE ($90/bulan, 50 thread). Karena solve tidak dihitung satuan, yang menaikkan tagihan hanyalah tingkat paralelisme, bukan frekuensi crawl.
Untuk tim di Indonesia, pola ini menutup pos biaya yang paling sulit diprediksi pada pekerjaan monitoring harga atau kontrak scraping lepas: volume boleh naik-turun, biaya CAPTCHA-nya tetap. Soal latensi, jalankan worker di region terdekat — AWS ap-southeast-3 (Jakarta) atau ap-southeast-1 (Singapura). Satu catatan kepatuhan: UU Pelindungan Data Pribadi (UU 27/2022) menjadikan prinsip "ambil hanya data yang boleh Anda proses, hindari data pribadi" aturan main yang wajar untuk setiap job otomatisasi.
Kesalahan umum di tahap injeksi token
| Gejala | Penyebab yang paling mungkin | Perbaikan |
|---|---|---|
| Token ditolak server | Token kedaluwarsa sebelum form terkirim | Suntikkan dan submit dalam 120 detik sejak token diterima |
| Sitekey tidak ditemukan | Widget disisipkan belakangan oleh JavaScript | Perpanjang WebDriverWait dan tunggu data-sitekey |
NoSuchElementException |
Selector tidak cocok dengan markup halaman | Periksa DOM halaman lalu sesuaikan selector |
| Versi ChromeDriver tidak cocok | Chrome ikut terbarui otomatis | Samakan ChromeDriver dengan versi Chrome terpasang |
| Halaman kembali ke form yang sama | Callback JavaScript belum dipanggil | Jalankan blok ___grecaptcha_cfg dari Langkah 4 |
Task lama tertahan di CAPCHA_NOT_READY |
Seluruh thread paket Anda sedang terpakai | Kurangi worker paralel atau naikkan jumlah thread |
Pertanyaan yang sering muncul
Bagaimana kalau form memakai callback, bukan tombol submit?
Panggil callback-nya lewat driver.execute_script() dengan token hasil solve sebagai argumen, seperti blok kedua di Langkah 4. Rinciannya ada di panduan callback reCAPTCHA v2.
Berapa lama token hasil solve masih bisa dipakai?
Perlakukan 120 detik sebagai batas aman. Setelah itu Anda perlu mengirim task baru, jadi jangan menumpuk token di antrean untuk dipakai belakangan.
Bisakah saya melewatkan Selenium dan cukup memakai requests?
Bisa, kalau sitekey sudah ada di HTML awal dan form dikirim lewat POST biasa; pendekatan itu jauh lebih ringan. Selenium tetap dibutuhkan ketika halaman merakit form lewat JavaScript atau saat Anda menjalankan pengujian end-to-end.
Paket mana yang tepat untuk 20 sesi Selenium paralel?
STANDARD ($30/bulan, 15 thread) belum cukup: lima sesi akan menunggu giliran. ADVANCE ($90/bulan, 50 thread) memberi ruang penuh sekaligus cadangan.
Apakah pola ini bisa dipakai untuk hCaptcha?
Belum. hCaptcha tidak didukung saat ini, begitu pula FunCaptcha (Arkose Labs), sedangkan GeeTest v4 masih berstatus segera hadir. Yang bisa Anda jalankan dengan pola di atas adalah reCAPTCHA v2 dan v3 (termasuk Enterprise), Cloudflare Turnstile dan Cloudflare Challenge, GeeTest v3, serta CAPTCHA gambar dan grid.