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:
- Kirim task (gambar atau
sitekey) kein.php. - Simpan task ID dari respons.
- Polling
res.phpsampai statusnya bukanCAPCHA_NOT_READY. - 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
sessionagar 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.