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:
- Kunci satu sesi egress (IP tetap).
- Muat halaman, ambil
sitekey. - Kirim task ke CaptchaAI, simpan task ID, polling sampai token siap.
- Kirim form dari IP yang sama.
- 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
- Menggabungkan Bright Data dengan CaptchaAI
- Sesi persisten vs rotasi per permintaan
- Pengaruh kualitas jalur egress terhadap tingkat penyelesaian
Rotasi yang rapi menekan jumlah tantangan; sisanya diselesaikan lewat API. Ambil API key CaptchaAI Anda dan sambungkan ke pipeline scraping.