Tutorials

pengaturan token GeeTest v3 di browser automation

Solve GeeTest v3 lewat CaptchaAI hanya butuh satu panggilan API. Bagian yang justru menggagalkan banyak skrip automation muncul sesudahnya: menaruh tiga nilai hasil solve — geetest_challenge, geetest_validate, dan geetest_seccode — tepat di tempat yang diharapkan halaman. Tempatnya bisa berupa hidden field di dalam form, callback JavaScript milik widget, atau payload XHR saat form dikirim. Artikel ini menunjukkan pola injeksi yang benar untuk Playwright, Puppeteer, dan Selenium, lengkap dengan kode Python dan JavaScript yang bisa langsung Anda pakai.

Konteksnya sederhana: tim QA dan engineer scraping di Indonesia sering menghadapi GeeTest v3 di halaman login dan registrasi, dan yang mereka butuhkan bukan teori, tapi cara memasukkan hasil solve ke sesi browser tanpa membuat widget menolak. Satu catatan kepatuhan: sesuai UU Pelindungan Data Pribadi (UU 27/2022), jalankan otomatisasi hanya pada sistem dan data yang memang Anda kelola atau miliki izinnya.

Secara garis besar, alurnya selalu empat langkah yang sama:

  1. Ekstrak gt dan challenge dari halaman.
  2. Kirim keduanya ke CaptchaAI dan tunggu hasil solve.
  3. Suntikkan tiga nilai balasan ke tempat yang tepat.
  4. Submit form atau request, lalu verifikasi server menerima.

Sebelum mulai: yang perlu disiapkan

Sebelum menyentuh kode, pastikan hal-hal berikut sudah siap:

  • API key CaptchaAI yang aktif dari dashboard Anda.
  • Salah satu framework terpasang: Playwright, Puppeteer, atau Selenium.
  • Akses ke halaman uji milik sendiri (mis. staging.example.com/qa-login) yang memuat widget GeeTest v3.

Tiga nilai yang dikembalikan GeeTest v3

CaptchaAI mengembalikan hasil dalam tiga bagian:

{
  "geetest_challenge": "a1b2c3d4e5...modified_challenge",
  "geetest_validate": "abc123def456_validate",
  "geetest_seccode": "abc123def456_validate|jordan"
}

Ketiganya wajib disuntikkan bersama. Jika satu saja hilang, server menolak verifikasi. Masing-masing punya peran: geetest_challenge menandai sesi, geetest_validate membuktikan challenge terselesaikan, dan geetest_seccode menyimpan hash untuk mendeteksi perubahan nilai.

Tiga tempat halaman mengharapkan token

Sebelum menulis kode, tentukan dulu mekanisme mana yang dipakai situs target, karena itu menentukan cara injeksi:

  • Hidden form field — nilai ditaruh di <input type="hidden"> lalu ikut terkirim saat form di-submit. Pola paling umum.
  • Callback JavaScript — widget memanggil fungsi seperti getValidate() atau callback onSuccess milik objek captchaObj. Situs membaca hasil dari sana, bukan dari field.
  • XHR payload — form dikirim lewat request POST asinkron, sehingga nilai harus disisipkan ke body request, bukan ke DOM.

Empat langkah berikut memakai urutan yang sama untuk setiap framework: ekstrak gt dan challenge, solve, lalu suntik tiga nilai.

Langkah 1: ekstrak gt dan challenge lalu solve

Bagian ini berlaku untuk semua framework. Ambil gt dan challenge, kirim ke CaptchaAI, dan tunggu hasilnya lewat polling:

import requests
import time

def solve_geetest(gt, challenge, page_url):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "geetest",
        "gt": gt,
        "challenge": challenge,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]  # Returns dict with three values
    raise TimeoutError("GeeTest solve timed out")

Langkah 2: injeksi di Playwright (Python)

Tangkap parameter dari respons register

GeeTest memuat parameter lewat respons register. Sadap respons tersebut untuk mendapat gt dan challenge:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()

    # Capture GeeTest registration response
    geetest_data = {}
    def capture_geetest(response):
        if "register" in response.url and response.status == 200:
            try:
                data = response.json()
                if "gt" in data and "challenge" in data:
                    geetest_data.update(data)
            except Exception:
                pass

    page.on("response", capture_geetest)
    page.goto("https://staging.example.com/qa-login")
    page.wait_for_selector(".geetest_holder")

    gt = geetest_data["gt"]
    challenge = geetest_data["challenge"]

Suntikkan ke hidden field

Setelah solve selesai, tulis ketiga nilai ke hidden field lalu submit:

# Solve with CaptchaAI
solution = solve_geetest(gt, challenge, page.url)

# Method 1: Set hidden form fields
page.evaluate(f"""
    const fields = {{
        'geetest_challenge': '{solution["geetest_challenge"]}',
        'geetest_validate': '{solution["geetest_validate"]}',
        'geetest_seccode': '{solution["geetest_seccode"]}'
    }};
    for (const [name, value] of Object.entries(fields)) {{
        let input = document.querySelector(`input[name="${{name}}"]`);
        if (!input) {{
            input = document.createElement('input');
            input.type = 'hidden';
            input.name = name;
            document.querySelector('form').appendChild(input);
        }}
        input.value = value;
    }}
""")

# Submit form
page.click("#submit-button")

Metode 2: picu callback GeeTest

Sebagian situs membaca hasil dari callback JavaScript, bukan dari form field. Untuk kasus ini, override getValidate dan picu event sukses:

page.evaluate(f"""
    // Find the GeeTest captcha object
    if (window.captchaObj) {{
        // Simulate a successful solve
        const result = {{
            geetest_challenge: '{solution["geetest_challenge"]}',
            geetest_validate: '{solution["geetest_validate"]}',
            geetest_seccode: '{solution["geetest_seccode"]}'
        }};

        // Override getValidate to return our solution
        window.captchaObj.getValidate = function() {{ return result; }};

        // Trigger the success callback
        const successEvent = new Event('geetest_success');
        document.dispatchEvent(successEvent);
    }}
""")

Langkah 3: injeksi di Puppeteer (JavaScript)

Polanya sama seperti Playwright: sadap respons register, solve, lalu isi hidden field sebelum klik submit.

const puppeteer = require('puppeteer');

async function solveAndInject() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();

  // Capture GeeTest params
  let gt, challenge;
  page.on('response', async (response) => {
    if (response.url().includes('register') && response.status() === 200) {
      try {
        const data = await response.json();
        if (data.gt && data.challenge) {
          gt = data.gt;
          challenge = data.challenge;
        }
      } catch (e) {}
    }
  });

  await page.goto('https://staging.example.com/qa-login');
  await page.waitForSelector('.geetest_holder');

  // Solve with CaptchaAI (implementation from earlier)
  const solution = await solveCaptcha(gt, challenge, page.url());

  // Inject the three values
  await page.evaluate((sol) => {
    // Set hidden inputs
    const form = document.querySelector('form');
    ['geetest_challenge', 'geetest_validate', 'geetest_seccode'].forEach(name => {
      let input = document.querySelector(`input[name="${name}"]`);
      if (!input) {
        input = document.createElement('input');
        input.type = 'hidden';
        input.name = name;
        form.appendChild(input);
      }
      input.value = sol[name];
    });
  }, solution);

  await page.click('#submit-button');
}

Langkah 4: injeksi di Selenium (Python)

Selenium tidak punya penyadap respons sebawaan seperti dua framework sebelumnya, jadi gt dan challenge diambil langsung dari atribut data-* pada elemen widget:

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

# Wait for GeeTest widget
WebDriverWait(driver, 15).until(
    EC.presence_of_element_located((By.CLASS_NAME, "geetest_holder"))
)

# Extract gt and challenge from the page
gt = driver.execute_script(
    "return document.querySelector('[data-gt]')?.dataset.gt"
)
challenge = driver.execute_script(
    "return document.querySelector('[data-challenge]')?.dataset.challenge"
)

# Solve with CaptchaAI
solution = solve_geetest(gt, challenge, driver.current_url)

# Inject via JavaScript
driver.execute_script(f"""
    var fields = {{
        'geetest_challenge': '{solution["geetest_challenge"]}',
        'geetest_validate': '{solution["geetest_validate"]}',
        'geetest_seccode': '{solution["geetest_seccode"]}'
    }};
    var form = document.querySelector('form');
    for (var name in fields) {{
        var input = document.querySelector('input[name="' + name + '"]');
        if (!input) {{
            input = document.createElement('input');
            input.type = 'hidden';
            input.name = name;
            form.appendChild(input);
        }}
        input.value = fields[name];
    }}
""")

driver.find_element(By.ID, "submit-button").click()

Saat situs submit lewat XHR

Jika form dikirim via XHR alih-alih POST form biasa, DOM tidak akan pernah membawa nilai Anda. Sadap request-nya dan sisipkan tiga nilai ke dalam body sebelum diteruskan:

# Playwright: Intercept the XHR and inject values
def handle_route(route):
    if "login" in route.request.url and route.request.method == "POST":
        # Modify the POST data to include our solution
        post_data = route.request.post_data
        # Add GeeTest values to the request
        route.continue_(post_data=modified_data)
    else:
        route.continue_()

page.route("**/api/login**", handle_route)

Untuk beban kerja QA login yang berjalan paralel — misalnya dari region seperti AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta) — model harga CaptchaAI berbasis thread memudahkan perencanaan biaya: paket BASIC ($15/bulan, 5 threads) untuk pengujian kecil hingga PREMIUM ($170/bulan, 100 threads) untuk volume tinggi, tanpa biaya per solve.

Cara memastikan injeksi berhasil

Sebelum menganggap alur selesai, konfirmasi tiga hal berikut secara berurutan:

  1. Buka DevTools, tab Network, dan pastikan request submit membawa ketiga nilai di body atau form data.
  2. Periksa respons server — kode sukses atau redirect ke halaman berikutnya menandakan verifikasi lolos.
  3. Ulangi pada sesi baru untuk memastikan hasilnya konsisten, bukan kebetulan satu kali.

Nilai GeeTest v3 cepat kedaluwarsa. Jalankan ekstraksi, solve, dan injeksi tanpa jeda panjang agar challenge masih berlaku saat disuntikkan.

Tabel pemecahan masalah

Masalah Penyebab Perbaikan
"GeeTest validation failed" Satu dari tiga nilai tidak ada Verifikasi ketiganya disuntikkan
Challenge kedaluwarsa sebelum injeksi Jeda terlalu lama antara ekstraksi dan solve Ekstrak dan solve secara berurutan
Form submit tapi nilai tidak disertakan Nama field atau selector form salah Cek form sesungguhnya untuk nama yang benar
Callback tidak terpicu Situs menggunakan nama callback kustom Temukan callback di opsi initGeetest
Nilai disuntikkan tapi widget masih tampil State widget tidak diperbarui Trigger success callback secara programatik

Pertanyaan umum

Apakah panduan ini berlaku untuk versi GeeTest terbaru?

Belum. Pola tiga nilai di sini khusus GeeTest v3, yang saat ini diselesaikan CaptchaAI. Untuk versi v4, dukungan masih berstatus segera hadir sehingga alurnya belum tersedia.

Kapan memilih injeksi form field, callback, atau XHR?

Pakai hidden field jika situs mengirim form biasa, callback jika situs membaca hasil dari objek captchaObj, dan intercept XHR jika submit dilakukan lewat request asinkron. Kalau ragu, buka DevTools dan lihat request apa yang muncul saat form dikirim manual.

Kenapa GeeTest v3 memakai tiga nilai terpisah, bukan satu token?

Karena tiap nilai punya fungsi berbeda dan saling mengunci: geetest_challenge mengikat sesi, geetest_validate menjadi bukti penyelesaian, dan geetest_seccode adalah hash anti-tampering. Server memeriksa ketiganya, jadi injeksi parsial selalu gagal.

Bisakah hasil solve GeeTest dipakai ulang untuk banyak request?

Tidak disarankan. Nilai GeeTest terikat pada sesi dan challenge tertentu serta cepat kedaluwarsa, sehingga solve baru per sesi jauh lebih andal daripada menyimpan dan memakai ulang token lama.

Artikel terkait

Langkah selanjutnya

Injeksi solusi GeeTest v3 di framework apa pun — ambil API key CaptchaAI Anda dan mulai solve challenge pertama.

Komentar dinonaktifkan untuk artikel ini.