Use Cases

Otomatisasi Portal Pemerintah dengan CAPTCHA Solving

Jika Anda mengotomatiskan booking janji temu visa, pengujian civic tech, atau pencarian catatan publik, hambatannya hampir selalu sama: sebuah CAPTCHA di depan form. Portal pemerintah umumnya hanya memakai salah satu dari tiga tipe — reCAPTCHA v2, image CAPTCHA, atau BLS CAPTCHA — dan CaptchaAI menangani ketiganya lewat satu API. Artikel ini menunjukkan pola integrasi Python untuk masing-masing, mulai dari portal BLS yang banyak dipakai pelamar visa Schengen di Indonesia.

Semua contoh menargetkan alur kerja yang Anda kelola sendiri: pengujian QA, form Anda, atau data publik yang boleh diproses. Sesuai UU 27/2022, olah hanya data yang berhak Anda akses.

Apa pun tipe CAPTCHA-nya, integrasinya mengikuti empat langkah yang sama:

  1. Kirim task (gambar atau sitekey) ke in.php.
  2. Simpan task ID dari respons.
  3. Polling res.php sampai statusnya bukan CAPCHA_NOT_READY.
  4. Pakai token atau teks hasil di form yang bersangkutan.

Booking janji temu visa BLS secara otomatis

Portal BLS memakai sistem CAPTCHA sendiri, dan CaptchaAI mendukungnya dengan tingkat keberhasilan tinggi. Contoh berikut men-download gambar CAPTCHA, mengirimnya, lalu menangani CAPTCHA di titik login maupun konfirmasi slot:

import requests
import time
import base64

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"


def solve_bls_captcha(captcha_image_url, session):
    """Solve BLS-specific CAPTCHA."""
    # Download CAPTCHA image
    img_resp = session.get(captcha_image_url)
    img_b64 = base64.b64encode(img_resp.content).decode()

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "base64",
        "body": img_b64,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(30):
        time.sleep(3)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]

    raise TimeoutError("BLS CAPTCHA timeout")


class BLSAppointmentBooker:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
        })

    def login(self, portal_url, email, password):
        """Login to BLS portal with CAPTCHA."""
        resp = self.session.get(portal_url)

        # Extract CAPTCHA image URL from page
        import re
        match = re.search(r'src="(/captcha[^"]+)"', resp.text)
        if match:
            captcha_url = portal_url.rstrip("/") + match.group(1)
            captcha_text = solve_bls_captcha(captcha_url, self.session)
        else:
            captcha_text = ""

        login_resp = self.session.post(portal_url, data={
            "email": email,
            "password": password,
            "captcha": captcha_text,
        })
        return login_resp.status_code == 200

    def check_appointment_slots(self, slots_url):
        """Check available appointment slots."""
        resp = self.session.get(slots_url)
        if resp.status_code == 200:
            return resp.json().get("available_slots", [])
        return []

    def book_slot(self, booking_url, slot_id, applicant_data):
        """Book an appointment slot, handling any CAPTCHA."""
        resp = self.session.get(booking_url)

        # Check for CAPTCHA on booking page
        import re
        match = re.search(r'src="(/captcha[^"]+)"', resp.text)
        if match:
            captcha_url = booking_url.rstrip("/") + match.group(1)
            captcha_text = solve_bls_captcha(captcha_url, self.session)
        else:
            captcha_text = ""

        resp = self.session.post(booking_url, data={
            "slot_id": slot_id,
            "captcha": captcha_text,
            **applicant_data,
        })

        return {
            "success": resp.status_code == 200,
            "confirmation": resp.json().get("confirmation_number"),
        }

Dua hal yang perlu diperhatikan pada pola ini:

  • CAPTCHA muncul di dua titik — login dan konfirmasi slot — jadi tangani keduanya.
  • Jaga semua langkah dalam satu session agar cookie dan konteks halaman tetap konsisten.

Pencarian catatan pengadilan dengan reCAPTCHA v2

Portal catatan pengadilan hampir selalu memakai reCAPTCHA v2. Kirim sitekey halaman, lalu tempel token yang dikembalikan ke g-recaptcha-response:

def solve_recaptcha(sitekey, pageurl):
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]
    raise TimeoutError("Timeout")


class CourtRecordSearcher:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {"http": proxy, "https": proxy}
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
        })

    def search_cases(self, court_url, search_params, sitekey):
        """Search court records with reCAPTCHA handling."""
        # Load search page
        self.session.get(court_url)

        # Solve CAPTCHA
        token = solve_recaptcha(sitekey, court_url)

        # Submit search with token
        resp = self.session.post(court_url, data={
            **search_params,
            "g-recaptcha-response": token,
        })

        if resp.status_code == 200:
            return self._parse_results(resp.text)
        return []

    def _parse_results(self, html):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")
        cases = []
        for row in soup.select("table.results tr")[1:]:
            cols = row.select("td")
            if len(cols) >= 4:
                cases.append({
                    "case_number": cols[0].get_text(strip=True),
                    "parties": cols[1].get_text(strip=True),
                    "date": cols[2].get_text(strip=True),
                    "status": cols[3].get_text(strip=True),
                })
        return cases

Image CAPTCHA di portal izin daerah

Banyak portal izin kota dan kabupaten masih memakai image CAPTCHA sederhana — tipe yang paling ringan ditangani. Kirim gambar sebagai base64, lalu polling hasilnya:

def solve_image_captcha(image_url, session):
    """Solve image-based CAPTCHA common on local government sites."""
    img = session.get(image_url)
    img_b64 = base64.b64encode(img.content).decode()

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "base64",
        "body": img_b64,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(20):
        time.sleep(3)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]

    raise TimeoutError("Image CAPTCHA timeout")

Fungsi yang sama bisa dipakai ulang di banyak portal daerah karena polanya seragam:

  • Ambil URL gambar CAPTCHA dari HTML halaman.
  • Kirim sebagai method=base64, lalu tempel teks hasilnya ke field CAPTCHA form.

Pencarian catatan publik secara batch

Untuk pencarian properti massal, solve ulang tiap beberapa permintaan dan pakai ulang session di antaranya. Contoh berikut men-solve tiap lima alamat dan menulis hasil ke CSV:

import csv


def batch_property_lookup(addresses, portal_url, sitekey, output_file):
    """Look up multiple property records, solving CAPTCHA per batch."""
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
    })

    results = []
    for i, address in enumerate(addresses):
        try:
            # Solve CAPTCHA every 5th request (or when required)
            if i % 5 == 0:
                token = solve_recaptcha(sitekey, portal_url)

            resp = session.post(portal_url, data={
                "address": address,
                "g-recaptcha-response": token,
            })

            if resp.status_code == 200:
                results.append({
                    "address": address,
                    "data": resp.json(),
                })

            time.sleep(3)  # Be respectful

        except Exception as e:
            results.append({"address": address, "error": str(e)})

    # Save results
    with open(output_file, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["address", "data", "error"])
        writer.writeheader()
        writer.writerows(results)

    return results

Untuk tim freelance scraping atau agensi price-monitoring, model harga berbasis thread CaptchaAI terasa pas: BASIC ($15/bulan, 5 thread) memberi lima solve bersamaan tanpa biaya per-CAPTCHA, dan naik ke ADVANCE ($90/bulan, 50 thread) saat volume bertambah. Throughput dibatasi jumlah thread, bukan kuota harian.


Peta tipe CAPTCHA per kategori portal

Sebagai rujukan cepat saat memutuskan pola mana yang dipakai, berikut tipe CAPTCHA yang paling sering muncul di tiap kategori portal:

Kategori Portal CAPTCHA Umum Contoh Situs Kasus Penggunaan
Visa/imigrasi BLS, reCAPTCHA v2 Portal BLS, USCIS Booking janji temu
DMV / kendaraan bermotor reCAPTCHA v2, image Situs DMV negara bagian Perpanjangan registrasi
Catatan pengadilan reCAPTCHA v2 PACER, pengadilan negara bagian Pencarian kasus
Izin/lisensi Image CAPTCHA Portal izin kota Submit aplikasi
Portal pajak reCAPTCHA v2 IRS, situs pajak negara bagian Cek status filing
Catatan publik Image CAPTCHA, reCAPTCHA Catatan county Pencarian properti/deed

Mengelola sesi dan timeout portal

Portal pemerintah kerap menerapkan session timeout pendek, dan tiap kategori punya toleransi berbeda. Sesuaikan strategi otomasi dengan batas waktu berikut:

  • Portal visa (5–10 menit): selesaikan seluruh alur dengan cepat, jangan menunda antar langkah.
  • Situs DMV (15 menit): refresh cookie sesi di tengah jalan bila alur panjang.
  • Catatan pengadilan (20–30 menit): pecah pencarian menjadi kelompok kecil.
  • Portal pajak (10–15 menit): gunakan egress jaringan persisten yang diotorisasi dengan IP yang sama.
  • Aplikasi izin (30 menit): simpan progress di setiap langkah.

Jika worker berjalan di cloud, dekatkan region ke target — misalnya AWS ap-southeast-3 (Jakarta) — agar latensi tidak memangkas jatah timeout yang sudah ketat.


Mengatasi masalah umum

Masalah Penyebab Solusi
Image CAPTCHA tidak dimuat Cookie sesi sudah expired Mulai sesi baru
"Session expired" di form Terlalu lama untuk solve validasi awal di staging atau gunakan solve yang lebih cepat
Jawaban CAPTCHA salah Gambar terdistorsi Laporkan gambar buruk via API
Portal memblokir otomasi Deteksi IP/UA Gunakan egress jaringan yang diotorisasi + UA asli
Error validasi form setelah CAPTCHA Token server-side sudah expired Solve CAPTCHA tepat sebelum submit

Pertanyaan yang sering diajukan

Berapa biaya untuk mengotomatiskan banyak portal sekaligus?

CaptchaAI menagih per thread bersamaan, bukan per solve. Paket BASIC ($15/bulan, 5 thread) memberi lima solve paralel dengan solve tak terbatas per thread; naik ke ADVANCE ($90/bulan, 50 thread) saat volume bertambah. Tidak ada kuota harian atau biaya per tipe CAPTCHA.

Bagaimana memastikan token reCAPTCHA tidak expired sebelum form terkirim?

Solve CAPTCHA tepat sebelum langkah POST, bukan di awal alur. Token reCAPTCHA v2 berlaku singkat, jadi jarak solve_recaptcha() ke submit dibuat sependek mungkin.

Apakah CaptchaAI benar-benar mendukung BLS CAPTCHA?

Ya, dengan tingkat keberhasilan tinggi — pakai method=bls untuk solve langsung, atau method=base64 untuk solve berbasis gambar seperti pada solve_bls_captcha di atas.

Mengapa portal tetap mendeteksi otomasi meski CAPTCHA sudah terselesaikan?

Token yang valid hanya melewati lapisan CAPTCHA; portal masih bisa menandai sinyal lain. Yang paling sering memicu deteksi:

  • User-Agent bawaan library HTTP alih-alih UA browser asli.
  • IP yang berpindah-pindah di tengah satu alur form.
  • Interval permintaan yang terlalu seragam dan cepat.

Pakai UA browser asli, egress jaringan yang diotorisasi dengan IP tetap, dan beri jeda wajar antar langkah.


Bacaan lanjutan

Komentar dinonaktifkan untuk artikel ini.