Use Cases

Cara Scraping Situs Ber-CAPTCHA dengan Python dan CaptchaAI

Scraper Python yang mendadak kena reCAPTCHA atau Turnstile bukan tanda proyeknya gagal — cukup tambahkan satu panggilan API solver sebelum submit form, pakai kombinasi requests + BeautifulSoup + CaptchaAI, tanpa browser penuh.

Pola ini favorit tim price-monitoring dan freelancer scraping Indonesia di Upwork atau Fastwork — jauh lebih murah dibanding Selenium tiap halaman.

Kenapa Pola Ini Lebih Hemat dari Selenium

Untuk banyak kasus scraping, kombinasi CaptchaAI + requests menang dari sisi biaya dan resource dibanding menjalankan Selenium atau Playwright penuh di setiap request:

  • Tidak perlu instalasi browser driver (ChromeDriver, GeckoDriver) atau flag --headless — cukup HTTP client biasa.
  • Pemakaian RAM dan CPU jauh lebih ringan, jadi satu VPS kecil bisa menjalankan ratusan task paralel selama thread mencukupi.
  • reCAPTCHA v3 biasanya selesai di bawah 4 detik dan Cloudflare Turnstile di bawah 10 detik, jadi latensi tambahan per request tetap kecil.
  • Cocok dideploy di region Asia Tenggara seperti AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta), maupun GCP asia-southeast2 (Jakarta) — latensi ke API CaptchaAI tetap singkat.

Yang Perlu Disiapkan

Sebelum menulis kode, pastikan lingkungan berikut sudah siap:

Persyaratan Detail
Python 3.7+ Dengan pip
requests pip install requests
beautifulsoup4 pip install beautifulsoup4
Kunci API CaptchaAI Dari captchaai.com

Yang tidak Anda perlukan untuk pola ini:

  • Instalasi Chrome, Chromium, atau browser lain
  • Driver seperti ChromeDriver atau GeckoDriver
  • Paket selenium atau playwright

Bangun Kelas CaptchaSolver yang Bisa Dipakai Ulang

Daripada menulis ulang logika submit-dan-polling tiap script, bungkus sekali dalam kelas berikut:

import requests
import time

class CaptchaSolver:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base = "https://ocr.captchaai.com"

    def _submit(self, params):
        params["key"] = self.api_key
        resp = requests.get(f"{self.base}/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit error: {resp.text}")
        return resp.text.split("|")[1]

    def _poll(self, task_id, timeout=300):
        deadline = time.time() + timeout
        while time.time() < deadline:
            time.sleep(5)
            resp = requests.get(f"{self.base}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id
            })
            if resp.text == "CAPCHA_NOT_READY":
                continue
            if resp.text.startswith("OK|"):
                return resp.text.split("|")[1]
            raise Exception(f"Solve error: {resp.text}")
        raise TimeoutError("Solve timed out")

    def solve_recaptcha_v2(self, site_key, page_url):
        task_id = self._submit({
            "method": "userrecaptcha",
            "googlekey": site_key,
            "pageurl": page_url
        })
        return self._poll(task_id)

    def solve_recaptcha_v3(self, site_key, page_url, action="verify"):
        task_id = self._submit({
            "method": "userrecaptcha",
            "googlekey": site_key,
            "pageurl": page_url,
            "version": "v3",
            "action": action
        })
        return self._poll(task_id)

    def solve_turnstile(self, site_key, page_url):
        task_id = self._submit({
            "method": "turnstile",
            "sitekey": site_key,
            "pageurl": page_url
        })
        return self._poll(task_id)

    def solve_image(self, image_base64):
        task_id = self._submit({
            "method": "base64",
            "body": image_base64
        })
        return self._poll(task_id)

Empat method menutup reCAPTCHA v2, v3, Turnstile, dan CAPTCHA gambar — pola kirim → simpan task ID → polling → pakai token, konsisten di seluruh API. Simpan kelas ini di modul terpisah, misalnya captcha_solver.py, supaya bisa di-import ke semua script scraping tanpa duplikasi kode.

Scraping Form ber-reCAPTCHA v2

Contoh berikut mengasumsikan form target memuat widget reCAPTCHA v2 standar (div.g-recaptcha) dan menerima submit lewat HTTP POST biasa — pola paling umum di form pencarian maupun form kontak:

from bs4 import BeautifulSoup
import requests

solver = CaptchaSolver("YOUR_API_KEY")
session = requests.Session()
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})

# Step 1: Load the page
url = "https://example.com/search"
page = session.get(url)
soup = BeautifulSoup(page.text, "html.parser")

# Step 2: Extract the site key
recaptcha_div = soup.find("div", class_="g-recaptcha")
site_key = recaptcha_div["data-sitekey"]

# Step 3: Solve the CAPTCHA
token = solver.solve_recaptcha_v2(site_key, url)

# Step 4: Submit the form with the token
form_data = {
    "q": "search term",
    "g-recaptcha-response": token
}
result = session.post(url, data=form_data)

# Step 5: Parse the results
result_soup = BeautifulSoup(result.text, "html.parser")
items = result_soup.find_all("div", class_="result-item")
for item in items:
    print(item.text.strip())

Jika situs mengembalikan halaman CAPTCHA lagi setelah submit, penyebab paling umum adalah nama field token yang salah atau token yang sudah kedaluwarsa — cek bagian troubleshooting di bawah untuk daftar lengkapnya.

Scraping Banyak Halaman di Balik CAPTCHA

def scrape_all_pages(base_url, site_key, max_pages=10):
    solver = CaptchaSolver("YOUR_API_KEY")
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    })
    all_results = []

    for page_num in range(1, max_pages + 1):
        page_url = f"{base_url}?page={page_num}"

        # Solve CAPTCHA for each page if needed
        token = solver.solve_recaptcha_v2(site_key, page_url)

        resp = session.get(page_url, params={
            "g-recaptcha-response": token,
            "page": page_num
        })

        soup = BeautifulSoup(resp.text, "html.parser")
        items = soup.find_all("div", class_="item")

        if not items:
            break

        all_results.extend([item.text.strip() for item in items])
        print(f"Page {page_num}: {len(items)} items")

        time.sleep(2)  # Polite delay

    return all_results

Jika CAPTCHA muncul di tiap halaman, solve_recaptcha_v2() dipanggil ulang per halaman seperti contoh di atas. Untuk ratusan halaman, kombinasikan dengan rotasi proxy untuk scraping ber-CAPTCHA agar tidak diblokir karena volume.

Tips praktis untuk scraping multi-halaman dalam skala besar:

  • Gunakan session yang sama di seluruh halaman supaya cookie tidak hilang antar request.
  • Tambahkan jeda (time.sleep) antar halaman agar traffic tidak terlihat abnormal.
  • Pantau saldo dan pemakaian thread — task solve paralel yang berlebihan bisa melampaui kuota thread pada paket Anda.

Menangani CAPTCHA Gambar (OCR)

Beberapa situs lokal — misalnya form pendaftaran atau portal pembanding harga — masih memakai CAPTCHA gambar klasik alih-alih reCAPTCHA. Alurnya beda karena tidak ada site key: gambar diunduh lalu di-encode ke base64 sebelum dikirim ke endpoint OCR CaptchaAI:

import base64

def scrape_with_image_captcha(url):
    solver = CaptchaSolver("YOUR_API_KEY")
    session = requests.Session()

    page = session.get(url)
    soup = BeautifulSoup(page.text, "html.parser")

    # Find the CAPTCHA image
    captcha_img = soup.find("img", {"id": "captcha-image"})
    captcha_url = captcha_img["src"]

    # Download and encode the image
    img_resp = session.get(captcha_url)
    img_base64 = base64.b64encode(img_resp.content).decode()

    # Solve
    captcha_text = solver.solve_image(img_base64)

    # Submit
    form_data = {
        "captcha": captcha_text,
        "username": "user"
    }
    result = session.post(url, data=form_data)
    return result.text

Retry dan Error Handling untuk Scraper Produksi

Scraper yang jalan tanpa pengawasan butuh logika percobaan ulang, bukan sekadar try-except sekali jalan. Kegagalan paling sering datang dari koneksi jaringan yang putus sesaat, task solve yang timeout, atau saldo yang habis di tengah batch:

def solve_with_retry(solver, site_key, page_url, max_retries=3):
    for attempt in range(max_retries):
        try:
            return solver.solve_recaptcha_v2(site_key, page_url)
        except Exception as e:
            if attempt == max_retries - 1:
                raise
            print(f"Attempt {attempt + 1} failed: {e}. Retrying...")
            time.sleep(2)

Untuk scraping volume besar, naikkan max_retries menjadi 5 dan gabungkan dengan exponential backoff (jeda yang meningkat eksponensial) pada bagian time.sleep supaya CaptchaAI maupun server target sama-sama tidak dibanjiri request saat terjadi gangguan sementara.

Troubleshooting: Error yang Sering Muncul

Masalah Penyebab Solusi
ERROR_WRONG_USER_KEY API key tidak valid Verifikasi key dari dashboard
ERROR_ZERO_BALANCE Saldo habis Isi ulang akun
Submit form mengembalikan halaman CAPTCHA lagi Token kedaluwarsa atau nama field salah Gunakan token segera; periksa nama field form
ConnectionError Masalah jaringan Tambahkan logika retry dengan exponential backoff
Hasil kosong setelah submit Situs memerlukan cookie/session Gunakan requests.Session() untuk mempertahankan cookie

Tip: sebelum debugging kode, cek dashboard CaptchaAI Anda terlebih dahulu — saldo dan status task sering jadi penyebab error yang sekilas terlihat seperti bug di script.

Pertanyaan yang Sering Diajukan

Apakah scraping dengan Python selalu butuh Selenium kalau ada CAPTCHA?

Tidak selalu. Kalau form bisa disubmit lewat HTTP POST biasa, requests + CaptchaAI lebih ringan. Selenium baru perlu jika situs merender JavaScript dulu.

Apakah CaptchaAI mendukung reCAPTCHA v3 dan Turnstile lewat script Python tanpa browser?

Ya, lewat method sama pada kelas CaptchaSolver di atas — tanpa browser, cukup panggil API dari script.

Bagaimana menjalankan penyelesaian CAPTCHA secara asynchronous untuk scraping ribuan halaman?

Gunakan aiohttp bersama API CaptchaAI agar banyak task solve berjalan bersamaan. Lihat integrasi aiohttp dengan CaptchaAI untuk polanya.

Berapa biaya solver CAPTCHA untuk proyek scraping skala freelance?

Paket BASIC ($15/bulan, 5 thread) biasanya cukup — solve per thread tidak dibatasi jumlahnya, tinggal naik ke STANDARD ($30/bulan, 15 thread) bila perlu.

Apakah scraping dengan CaptchaAI melanggar UU PDP?

Sepanjang Anda hanya mengambil data publik yang memang berhak Anda proses, ini tidak melanggar UU Pelindungan Data Pribadi (UU 27/2022) maupun UU ITE.

Panduan Terkait

Komentar dinonaktifkan untuk artikel ini.