Tutorials

Ekstraksi Parameter reCAPTCHA dari Source Halaman

Dua parameter selalu wajib untuk setiap solve reCAPTCHA lewat CaptchaAI: googlekey (sitekey) dan pageurl. Sisanya menyesuaikan versi — action untuk v3, flag enterprise untuk Enterprise, dan data-s untuk sebagian situs milik Google. Kalau satu saja meleset, task Anda ditolak atau mengembalikan token yang tidak valid.

Karena itu urutannya jelas: ekstrak dulu dengan benar, baru kirim ke in.php. Ada empat sumber yang bisa Anda gunakan, dari yang paling gampang ke yang paling teknis:

  1. Atribut HTML seperti data-sitekey pada widget v2.
  2. Script tag api.js / enterprise.js untuk sitekey v3 dan Enterprise.
  3. URL iframe reCAPTCHA ketika sitekey muncul sebagai parameter k=.
  4. Konfigurasi grecaptcha.render() untuk widget yang dibangun via JavaScript.

Parameter apa yang dibutuhkan tiap versi reCAPTCHA

Sebelum menulis kode, pastikan Anda tahu versi mana yang sedang dihadapi. Tabel ini merangkum parameter yang harus dikumpulkan untuk masing-masing tipe:

Parameter v2 Standard v2 Invisible v3 Enterprise
googlekey (sitekey) Wajib Wajib Wajib Wajib
pageurl Wajib Wajib Wajib Wajib
invisible 1
action Wajib Kadang
data-s Kadang Kadang
enterprise 1

Sitekey dan pageurl tidak pernah bisa dilewati; parameter lain mengikuti versi yang terdeteksi.

Cara 1: baca langsung dari atribut HTML

Ini kasus paling umum dan paling mudah. Widget reCAPTCHA v2 menaruh sitekey di atribut data-sitekey, dan mode invisible ditandai data-size="invisible". Untuk situs yang me-render widget di HTML awal, satu request requests.get sudah cukup.

import re
import requests

url = "https://staging.example.com/qa-login"
html = requests.get(url).text

# Find data-sitekey
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', html)
if match:
    sitekey = match.group(1)
    print(f"Sitekey: {sitekey}")

# Check if invisible
invisible_match = re.search(r'data-size=["\']invisible["\']', html)
is_invisible = bool(invisible_match)
print(f"Invisible: {is_invisible}")

# Find callback
callback_match = re.search(r'data-callback=["\'](\w+)["\']', html)
callback = callback_match.group(1) if callback_match else None
print(f"Callback: {callback}")

# Check for data-s (Google-owned sites)
data_s_match = re.search(r'data-s=["\']([^"\']+)["\']', html)
data_s = data_s_match.group(1) if data_s_match else None
print(f"data-s: {data_s}")

Regex di atas gagal kalau reCAPTCHA baru disuntikkan setelah halaman dijalankan di browser. Untuk itu, buka halaman dengan Puppeteer, tunggu network idle, lalu baca atributnya dari DOM yang sudah jadi:

const puppeteer = require('puppeteer');

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

const params = await page.evaluate(() => {
  const widget = document.querySelector('.g-recaptcha');
  if (!widget) return null;

  return {
    sitekey: widget.getAttribute('data-sitekey'),
    size: widget.getAttribute('data-size'),
    callback: widget.getAttribute('data-callback'),
    dataS: widget.getAttribute('data-s'),
    invisible: widget.getAttribute('data-size') === 'invisible',
  };
});

console.log(params);

Cara 2: gali dari script tag

reCAPTCHA v3 dan Enterprise jarang memakai data-sitekey. Sitekey-nya justru tertanam di parameter render= pada URL script, dan action-nya tersembunyi di dalam kode JavaScript. Mulai dari sitekey:

# Find sitekey from script src
v3_match = re.search(
    r'recaptcha/(?:api|enterprise)\.js\?.*?render=([A-Za-z0-9_-]+)',
    html
)
if v3_match:
    sitekey = v3_match.group(1)
    print(f"v3 Sitekey: {sitekey}")

# Check enterprise
is_enterprise = 'enterprise.js' in html
print(f"Enterprise: {is_enterprise}")

Keberadaan enterprise.js di source adalah sinyal paling andal bahwa Anda menghadapi reCAPTCHA Enterprise, sehingga flag enterprise harus disertakan saat kirim task. Untuk v3, action bukan atribut HTML melainkan argumen pada pemanggilan grecaptcha.execute:

# Search for grecaptcha.execute calls
action_match = re.search(
    r'grecaptcha\.execute\s*\([^,]+,\s*\{[^}]*action\s*:\s*["\']([^"\']+)',
    html
)
if action_match:
    action = action_match.group(1)
    print(f"Action: {action}")

Cara 3: tarik sitekey dari src iframe

Kadang reCAPTCHA di-render di dalam iframe dan sitekey muncul sebagai parameter k= pada URL iframe. Ini alternatif ketika atribut data-sitekey tidak ada di markup utama:

# Find reCAPTCHA iframe
iframe_match = re.search(
    r'<iframe[^>]+src=["\']([^"\']*recaptcha/api2/anchor[^"\']*)["\']',
    html
)
if iframe_match:
    iframe_src = iframe_match.group(1)
    sitekey_match = re.search(r'k=([A-Za-z0-9_-]+)', iframe_src)
    if sitekey_match:
        sitekey = sitekey_match.group(1)
        print(f"Iframe sitekey: {sitekey}")

Cara 4: baca konfigurasi grecaptcha.render

Sebagian situs membangun widget lewat grecaptcha.render() dengan objek konfigurasi. Di sini sitekey, callback, dan size berada dalam satu blok yang bisa Anda urai sekaligus:

# Find grecaptcha.render calls
render_match = re.search(
    r'grecaptcha\.render\s*\([^,]*,\s*\{([^}]+)\}',
    html
)
if render_match:
    config = render_match.group(1)
    sk = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', config)
    cb = re.search(r'callback\s*:\s*["\']?(\w+)', config)
    sz = re.search(r'size\s*:\s*["\'](\w+)', config)
    print(f"Sitekey: {sk.group(1) if sk else 'not found'}")
    print(f"Callback: {cb.group(1) if cb else 'not found'}")
    print(f"Size: {sz.group(1) if sz else 'not found'}")

Satu fungsi untuk semua kasus

Daripada memilih cara satu per satu, gabungkan keempatnya dalam satu fungsi yang mencoba tiap sumber sitekey secara berurutan, lalu mendeteksi versi dan parameter tambahan. Pola seperti ini biasa dipakai tim scraping freelance di Indonesia yang menghadapi banyak layout halaman berbeda dalam satu proyek — satu fungsi tahan-banting lebih hemat waktu daripada menulis parser khusus per situs.

import re
import requests

def extract_recaptcha_params(url):
    html = requests.get(url, timeout=15).text
    params = {"pageurl": url}

    # Sitekey from data-sitekey
    sk = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)', html)
    if sk:
        params["sitekey"] = sk.group(1)

    # Sitekey from script render parameter (v3)
    if "sitekey" not in params:
        v3 = re.search(r'render=([A-Za-z0-9_-]{20,})', html)
        if v3:
            params["sitekey"] = v3.group(1)

    # Sitekey from iframe
    if "sitekey" not in params:
        iframe = re.search(r'recaptcha.*?k=([A-Za-z0-9_-]+)', html)
        if iframe:
            params["sitekey"] = iframe.group(1)

    # Sitekey from grecaptcha.render
    if "sitekey" not in params:
        render = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', html)
        if render:
            params["sitekey"] = render.group(1)

    # Version detection
    if re.search(r'data-size=["\']invisible', html):
        params["invisible"] = True
    if 'enterprise.js' in html:
        params["enterprise"] = True

    # Action (v3)
    action = re.search(
        r'action\s*:\s*["\']([^"\']+)',
        html[html.find('grecaptcha.execute'):] if 'grecaptcha.execute' in html else ''
    )
    if action:
        params["action"] = action.group(1)

    # data-s
    ds = re.search(r'data-s=["\']([^"\']+)', html)
    if ds:
        params["data_s"] = ds.group(1)

    # Callback
    cb = re.search(r'data-callback=["\'](\w+)', html)
    if cb:
        params["callback"] = cb.group(1)

    return params

# Usage
params = extract_recaptcha_params("https://staging.example.com/qa-login")
for k, v in params.items():
    print(f"  {k}: {v}")

Untuk halaman v2 invisible sederhana, hasilnya kira-kira seperti ini:

  pageurl: https://staging.example.com/qa-login
  sitekey: 6Le-SITEKEY-abc123
  invisible: True
  callback: onCaptchaComplete

Kirim parameter hasil ekstraksi ke CaptchaAI

Setelah dictionary params terisi, susun payload untuk in.php. Parameter opsional hanya ditambahkan bila terdeteksi, sehingga v2 standar tidak ikut membawa flag yang tidak relevan:

data = {
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": params["sitekey"],
    "pageurl": params["pageurl"],
    "json": "1",
}

if params.get("invisible"):
    data["invisible"] = "1"
if params.get("enterprise"):
    data["enterprise"] = "1"
if params.get("action"):
    data["action"] = params["action"]
if params.get("data_s"):
    data["data-s"] = params["data_s"]

resp = requests.post("https://ocr.captchaai.com/in.php", data=data).json()

CaptchaAI menangani reCAPTCHA v2, v3, dan Enterprise, dan penagihannya berbasis thread — Anda membayar jumlah solve serentak, bukan per token. Paket mulai dari BASIC ($15/bulan, 5 thread) sampai VIP-3 ($7,500/bulan, 5.000 thread), semuanya dengan solve tanpa batas per thread. Jadi biaya tidak melonjak hanya karena satu halaman kebetulan pakai Enterprise dengan action.

Kalau parameter sulit ditemukan

Empat masalah ini yang paling sering muncul saat ekstraksi, beserta cara menanganinya:

  • Tidak ada sitekey sama sekali — halaman kemungkinan me-render widget secara dinamis. Buka dengan Puppeteer atau Selenium, jangan andalkan HTML statis.
  • Sitekey salah — ada beberapa instance reCAPTCHA di halaman. Pastikan Anda mengambil widget yang benar-benar terhubung ke form yang di-submit.
  • Action tidak ketemu — biasanya didefinisikan di file JS eksternal. Fetch file JavaScript yang ditautkan lalu cari pemanggilan grecaptcha.execute di sana.
  • data-s berubah tiap request — Google me-regenerate nilainya, jadi ekstrak data-s yang baru untuk setiap solve.

Sesuai UU Pelindungan Data Pribadi (UU 27/2022), lakukan ekstraksi hanya pada halaman yang memang berhak Anda proses dan hindari mengambil data pribadi. Ini bukan nasihat hukum, hanya pengingat praktis.

Pertanyaan umum

Bagaimana cara membedakan versi reCAPTCHA dari source halaman?

Lihat script dan atributnya. Widget .g-recaptcha dengan data-sitekey biasanya v2; data-size="invisible" menandai v2 invisible; sitekey di parameter render= pada api.js menandai v3; dan keberadaan enterprise.js menandai Enterprise.

Kenapa sitekey tidak muncul di HTML dan bagaimana mengatasinya?

Karena widget baru disuntikkan setelah JavaScript berjalan, sehingga tidak ada di HTML statis hasil requests.get. Buka halaman dengan headless browser seperti Puppeteer atau Selenium, tunggu render selesai, lalu baca atribut dari DOM.

Apakah sitekey perlu dirahasiakan seperti API key?

Tidak. Sitekey adalah kunci publik yang memang terlihat di source halaman dan aman dibagikan. Yang wajib dirahasiakan adalah API key CaptchaAI Anda, karena itulah yang menagih thread di akun Anda.

Apakah action selalu wajib dikirim?

Untuk reCAPTCHA v3 ya, karena skor terikat pada action tertentu. Untuk v2 standar dan invisible tidak diperlukan, dan pada Enterprise sifatnya kondisional tergantung konfigurasi situs.

Mulai sekarang

Ambil API key Anda di captchaai.com, jalankan fungsi ekstraksi di atas, lalu kirim parameter hasilnya untuk solve yang stabil. Lihat juga mekanisme callback reCAPTCHA v2 dan deteksi trigger reCAPTCHA v2 invisible untuk langkah lanjutannya.

Komentar dinonaktifkan untuk artikel ini.