Explainers

Rotasi IP dan penyelesaian CAPTCHA: strategi egress untuk scraping

Rotasi IP tidak menghilangkan CAPTCHA, tetapi menentukan seberapa sering Anda bertemu CAPTCHA. Aturannya dua: keluarkan trafik dari IP yang reputasinya wajar, dan jangan pernah mengganti IP di tengah satu alur penyelesaian CAPTCHA. Tantangan yang tetap muncul diserahkan ke solver API seperti CaptchaAI.

Di bawah ini: tiga pola rotasi egress, lima praktik operasional penurun tantangan, dan pola integrasi Python-nya.


Aturan nomor satu: satu IP untuk satu siklus token

Token reCAPTCHA atau Turnstile terikat pada konteks sesi tempat tantangan dimuat. Kalau gateway mengganti IP antara "muat halaman" dan "kirim form", token yang sudah diselesaikan ditolak server — di log yang terlihat hanya form gagal tanpa alasan jelas, jadi solver sering disalahkan.

Urutan yang benar:

  1. Kunci satu sesi egress (IP tetap).
  2. Muat halaman, ambil sitekey.
  3. Kirim task ke CaptchaAI, simpan task ID, polling sampai token siap.
  4. Kirim form dari IP yang sama.
  5. Baru lepas sesi dan rotasi untuk target berikutnya.

Selama langkah 1–4, rotasi adalah musuh.


Mengapa asal IP menentukan tingkat tantangan

Sistem CAPTCHA — reCAPTCHA khususnya — mengecek reputasi IP sebelum menentukan kerasnya tantangan. IP residensial punya riwayat bersih karena dipakai manusia; rentang IP pusat data sudah lama ditandai karena trafiknya mayoritas otomatis.

Jenis egress Sumber IP Frekuensi CAPTCHA Alasan
Pusat data Cloud/hosting Tinggi (30–70%) Rentang IP dikenal dan ditandai
Residensial ISP rumah asli Rendah (5–15%) Menyerupai pengguna biasa
Seluler Operator seluler Sangat rendah (1–5%) Dipakai ribuan pelanggan (CGNAT)
ISP statis Residensial, alamat tetap Rendah (5–10%) Reputasi baik, stabil

Konteks lokal yang sering terlewat: banyak tim di Indonesia menjalankan worker di AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta), lalu bingung kenapa tantangan melonjak dibanding saat diuji dari laptop kantor. Penyebabnya selisih reputasi IP.


Tiga pola rotasi dan kapan memakainya

1. Rotasi per permintaan

Setiap permintaan keluar dari IP baru — default pada sebagian besar gateway.

import requests

proxies = {
    "http": "http://user:pass@gateway.proxy.com:7777",
    "https": "http://user:pass@gateway.proxy.com:7777",
}

# Each request gets a new IP
for url in urls:
    resp = requests.get(url, proxies=proxies, timeout=30)
    # New IP after each request

Cocok untuk: halaman publik independen dalam jumlah besar — daftar harga, katalog, kategori. Risiko CAPTCHA: rendah per permintaan, tetapi sesi tidak bertahan — jangan dipakai untuk alur bertoken.

2. Sesi persisten

Satu session ID mengunci satu IP beberapa menit — cukup untuk satu alur penuh.

import random
import string

def get_sticky_session(duration_min=10):
    session_id = "".join(random.choices(string.ascii_lowercase, k=8))
    return {
        "http": f"http://user-session-{session_id}:pass@gateway.proxy.com:7777",
        "https": f"http://user-session-{session_id}:pass@gateway.proxy.com:7777",
    }

# Same IP for the whole CAPTCHA workflow
session_proxy = get_sticky_session(duration_min=10)

# Step 1: Load page
resp = requests.get("https://staging.example.com/qa-form", proxies=session_proxy)

# Step 2: Solve CAPTCHA (same IP)
token = solve_captcha("https://staging.example.com/qa-form", sitekey)

# Step 3: Submit (same IP — required for token validity)
resp = requests.post("https://target.com/submit", proxies=session_proxy, data={
    "g-recaptcha-response": token,
})

Cocok untuk: form yang dilindungi CAPTCHA, login QA milik sendiri, checkout multi-langkah di staging. Risiko CAPTCHA: sangat rendah. Contoh di atas mengikuti aturan nomor satu: muat → selesaikan → kirim, semuanya dari satu IP.

3. Rotasi per domain

Setiap domain mendapat satu IP tetap.

domain_sessions = {}

def get_domain_proxy(domain):
    """Same IP per domain, different IP per domain."""
    if domain not in domain_sessions:
        session_id = "".join(random.choices(string.ascii_lowercase, k=8))
        domain_sessions[domain] = get_sticky_session()
    return domain_sessions[domain]

# site-a.com always uses the same IP
proxy_a = get_domain_proxy("site-a.com")
# site-b.com gets a different IP
proxy_b = get_domain_proxy("site-b.com")

Berguna saat memantau beberapa situs: tiap domain melihat "pengunjung" yang konsisten, tanpa IP dipakai ulang antar-domain.


Lima praktik operasional yang menurunkan tingkat tantangan

Cocokkan geo dengan target

# Target site is US-based? Use US residential IP
us_proxy = "http://user-country-us:pass@gateway.proxy.com:7777"

# Target is Germany? Use DE residential IP
de_proxy = "http://user-country-de:pass@gateway.proxy.com:7777"

Ketidakcocokan geografis adalah pemicu tantangan paling mudah dihindari. Kalau targetnya situs Indonesia, pakai IP Indonesia — konsistensi geo, Accept-Language, dan zona waktu lebih menentukan daripada besarnya kumpulan.

Pakai jeda yang masuk akal

import time
import random

def human_pace_requests(urls, proxy):
    results = []
    for url in urls:
        resp = requests.get(url, proxies=proxy, timeout=30)
        results.append(resp)

        # Random delay between requests
        delay = random.uniform(2, 8)
        time.sleep(delay)

    return results
Laju permintaan Risiko CAPTCHA
1 permintaan/detik Tinggi (pola mesin)
1 permintaan/5–10 detik Sedang
1 permintaan/10–30 detik Rendah
Acak 3–15 detik Sangat rendah

Jeda acak mengalahkan jeda tetap: interval yang persis sama adalah sinyal otomasi.

Kirim header yang konsisten

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/126.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "DNT": "1",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
}

resp = requests.get(url, proxies=proxy, headers=headers)

Header harus konsisten satu sama lain dan dengan lokasi IP-nya: User-Agent Chrome terbaru dengan Accept-Language yang janggal justru lebih mencurigakan.

Tangani pemblokiran IP dengan rapi

def fetch_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        # New proxy for each retry
        proxy = get_sticky_session()

        try:
            resp = requests.get(url, proxies=proxy, timeout=30)

            if resp.status_code == 403:
                print(f"IP banned, rotating... (attempt {attempt + 1})")
                time.sleep(5)
                continue

            if resp.status_code == 429:
                print(f"Rate limited, backing off...")
                time.sleep(30)
                continue

            return resp

        except requests.exceptions.ProxyError:
            print(f"Proxy failed, rotating...")
            continue

    raise Exception(f"Failed after {max_retries} retries")

Perlakukan 403 sebagai sinyal ganti sesi dan 429 sebagai sinyal melambat. Merotasi IP saat kena 429 hanya menghabiskan kumpulan IP pada laju yang tetap kelewat cepat.

Panaskan IP baru

def warm_up_proxy(proxy):
    """Visit neutral sites before target to build session trust."""
    warm_urls = [
        "https://www.google.com",
        "https://www.wikipedia.org",
    ]
    for url in warm_urls:
        try:
            requests.get(url, proxies=proxy, timeout=15)
            time.sleep(random.uniform(2, 5))
        except Exception:
            pass

Sesi yang langsung menghantam halaman terproteksi terlihat lebih mesin daripada sesi berisi riwayat.


Menyambungkan rotasi dengan CaptchaAI

Untuk tantangan yang tetap muncul, alurnya pola empat langkah: kirim → simpan task ID → polling → pakai token.

import requests
import time
import re
import random
import string

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


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

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

    raise TimeoutError("Timeout")


def scrape_url(url, proxy_config):
    """Complete scrape with proxy + CAPTCHA solving."""
    session_id = "".join(random.choices(string.ascii_lowercase, k=8))
    proxy = {
        "http": f"http://user-session-{session_id}:{proxy_config['pass']}@{proxy_config['host']}",
        "https": f"http://user-session-{session_id}:{proxy_config['pass']}@{proxy_config['host']}",
    }

    resp = requests.get(url, proxies=proxy, timeout=30)

    match = re.search(r'data-sitekey="([^"]+)"', resp.text)
    if match:
        token = solve_recaptcha(url, match.group(1))
        resp = requests.post(
            url.replace("/form", "/submit"),
            proxies=proxy,
            data={"g-recaptcha-response": token},
        )

    return resp.text

Detail penting: proxy dibuat sekali lalu dipakai ulang untuk requests.get maupun requests.post — jaga properti itu saat memfaktorkan ulang. Parameter in.php berbeda per tipe (method=userrecaptcha, method=turnstile, method=geetest), tetapi polling-nya identik.

Soal cakupan: CaptchaAI mendukung reCAPTCHA v2/v3 (termasuk Enterprise), Cloudflare Turnstile dan Challenge, GeeTest v3, CAPTCHA gambar/OCR, grid, dan BLS — plus CaptchaFox (beta), Friendly Captcha (beta), dan Lemin (beta). hCaptcha dan FunCaptcha belum didukung; GeeTest v4 masih segera hadir.


Menekan biaya: egress mahal, thread tidak

Kedua komponen biaya di alur ini bermodel berbeda. Egress residensial umumnya ditagih per gigabyte — makin banyak halaman yang ditarik lewat jalur itu, makin mahal. CaptchaAI menagih per thread bersamaan dengan solve tak terbatas: BASIC ($15/bulan, 5 thread) dan STANDARD ($30/bulan, 15 thread) menutupi kebutuhan sebagian besar freelancer scraping dan agensi pemantau harga, sementara ADVANCE ($90/bulan, 50 thread) atau PREMIUM ($170/bulan, 100 thread) masuk akal begitu banyak worker berjalan paralel. Di atasnya: CORPORATE ($240/bulan, 150 thread), ENTERPRISE ($300/bulan, 200 thread), VIP-1 ($1,500/bulan, 1.000 thread), VIP-2 ($4,500/bulan, 3.000 thread), dan VIP-3 ($7,500/bulan, 5.000 thread). Artinya biaya CAPTCHA mengikuti konkurensi, bukan jumlah tantangan.

Strategi Dampak
Egress premium hanya untuk halaman yang berpotensi menantang Tagihan bandwidth turun
Halaman daftar lewat jalur murah, detail lewat premium Volume byte premium turun
Naikkan jumlah thread, bukan jumlah akun solver Biaya tetap, throughput naik
Buang zona IP berkualitas buruk Percobaan pertama lebih sering berhasil

Catatan kepatuhan di Indonesia: UU Pelindungan Data Pribadi (UU 27/2022) membuat prinsip "ambil hanya data yang Anda berhak proses" bukan sekadar etiket.


Diagnosis cepat saat tingkat tantangan melonjak

Gejala Penyebab paling mungkin Tindakan
CAPTCHA di hampir setiap halaman Kumpulan IP buruk Ganti zona atau penyedia egress
Token ditolak setelah solve berhasil IP berubah antara solve dan submit Kunci sesi persisten
Kode error 407 Format autentikasi gateway salah Cek format username dari penyedia
Respons sangat lambat Gateway kelebihan beban Coba di luar jam sibuk
Sesi putus di tengah alur TTL sesi terlalu pendek Minta durasi sesi lebih panjang

Pertanyaan umum

Apakah rotasi IP bisa menggantikan solver CAPTCHA?

Tidak. Rotasi menurunkan frekuensi tantangan, bukan menyelesaikannya: egress mengurus reputasi, solver mengurus token.

Berapa lama sesi persisten sebaiknya bertahan?

Cukup untuk satu alur penuh, dari pemuatan halaman sampai pengiriman form. Sepuluh menit lapang untuk sebagian besar kasus; untuk alur panjang minta TTL lebih besar.

Apakah menjalankan worker di region Jakarta atau Singapura menurunkan tingkat CAPTCHA?

Tidak. Region memengaruhi latensi, bukan reputasi IP: worker di ap-southeast-3 tetap keluar dari rentang IP pusat data. Yang menentukan jalur egress.

Berapa thread CaptchaAI yang saya butuhkan untuk pipeline scraping?

Hitung dari tantangan yang berjalan bersamaan pada puncak beban, bukan total harian. Lima worker paralel yang menunggu token berarti lima thread — tercakup BASIC ($15/bulan, 5 thread).

Bagaimana kalau target saya memakai hCaptcha?

Belum. hCaptcha tidak didukung, begitu pula FunCaptcha, dan GeeTest v4 masih segera hadir — untuk tipe itu Anda memerlukan layanan lain.


Bacaan lanjutan


Rotasi yang rapi menekan jumlah tantangan; sisanya diselesaikan lewat API. Ambil API key CaptchaAI Anda dan sambungkan ke pipeline scraping.

Komentar dinonaktifkan untuk artikel ini.