Memahami alasan request diblokir dan cara mengatasinya dengan proxy: jenis-jenis proxy, rotasi otomatis lewat ProxyRotator, strategi rotasi kustom, override proxy per request, deteksi serta retry request yang diblokir, dan spoofing header serta TLS fingerprint agar request sulit dikenali sebagai bot.

Di episode 11 kalian sudah membangun spider pertama: mendefinisikan start_urls, menulis parse callback, mengikuti link antar halaman, mengatur concurrency, dan memakai multi-session untuk merutekan request ke fetcher yang berbeda. Semua itu bekerja mulus — sampai website mulai menjawab dengan status 403 atau 429.
Episode ini membahas dua senjata utama untuk bertahan hidup saat skala crawl naik: proxy rotation dan anti-blocking. Kalian akan belajar memilih jenis proxy, merotasinya otomatis dengan ProxyRotator, menangani request yang diblokir, dan memakai impersonate serta stealthy_headers untuk membuat request kalian sedekat mungkin dengan browser asli.
Sebelum menyalahkan proxy, pahami dulu kenapa server menolak request kalian. Blokir biasanya berlapis dan punya tiga sumber utama:
429 (Too Many Requests) atau 503 dengan header retry, karena kalian melebihi kuota per detik.Proxy menyelesaikan masalah IP dan rate limit: dengan banyak IP, tekanan tersebar. Fingerprinting diselesaikan oleh impersonate yang sudah kalian kenal sejak episode 3. Keduanya saling melengkapi, bukan pengganti.
Tidak semua proxy setara. Jenisnya menentukan kecepatan, harga, dan seberapa mirip IP kalian dengan pengguna biasa:
Pilihannya strategi bisnis: untuk prototipe dan halaman publik, datacenter cukup. Untuk target dengan Cloudflare ketat, mulailah dengan residential.
Cara paling cepat menguji proxy adalah lewat parameter proxy di Fetcher — tanpa perlu struktur spider sama sekali:
from scrapling import Fetcher
page = Fetcher.get(
"https://httpbin.org/ip",
proxy="http://user:pass@proxy.example:8080",
)
print(page.text)Formatnya skema://kredensial@host:port. Satu proxy dipakai untuk semua request di session itu. Cara ini bagus untuk uji coba, tapi rapuh di skala besar: kalau IP itu kena ban, seluruh crawl ikut berhenti. Di sinilah rotasi otomatis berperan.
ProxyRotator mengelola daftar proxy dan memilih proxy berikutnya untuk setiap request secara otomatis. Default-nya rotasi cyclic — bergantian berurutan dan kembali ke awal setelah sampai ujung. Ia thread-safe sehingga aman dibagikan lintas request paralel:
from scrapling import FetcherSession, ProxyRotator
rotator = ProxyRotator([
"http://proxy1.example:8080",
"http://user:pass@proxy2.example:8080",
"http://proxy3.example:8080",
])
with FetcherSession(proxy_rotator=rotator, impersonate="chrome") as session:
page1 = session.get("https://example.com/page1")
page2 = session.get("https://example.com/page2")
page3 = session.get("https://example.com/page3")Perhatikan bahwa proxy_rotator tidak boleh dipakai bersamaan dengan proxy statis di session yang sama — pilih salah satu. Proxy yang terpakai bisa dilacak lewat page1.meta["proxy"]. Di dalam spider, rotator dipasang lewat configure_sessions:
from scrapling import ProxyRotator
from scrapling.fetchers import FetcherSession
from scrapling.spiders import Spider, Response
class KatalogSpider(Spider):
name = "katalog"
start_urls = ["https://example.com/products"]
def configure_sessions(self, manager):
rotator = ProxyRotator([
"http://proxy1.example:8080",
"http://user:pass@proxy2.example:8080",
])
manager.add("default", FetcherSession(proxy_rotator=rotator))
async def parse(self, response: Response):
for product in response.css(".product"):
yield {
"nama": product.css("h2::text").get(),
"harga": product.css(".price::text").get(),
}Dengan pola ini, tiap request otomatis memakai IP berikutnya tanpa kode manual. Untuk session berbasis browser (misalnya StealthySession), Scrapling membuka satu browser context per proxy — karena browser tidak bisa mengganti proxy per tab.
Rotasi cyclic mudah ditebak kalau poolnya kecil. ProxyRotator menerima fungsi strategi kustom dengan tanda tangan strategy(proxies, current_index) yang mengembalikan pasangan proxy terpilih dan index berikutnya. Contoh strategi acak dan berbobot:
import random
from scrapling import ProxyRotator
def random_strategy(proxies, current_index):
idx = random.randint(0, len(proxies) - 1)
return proxies[idx], idx
def weighted_strategy(proxies, current_index):
weights = [60] + [40 // (len(proxies) - 1)] * (len(proxies) - 1)
proxy = random.choices(proxies, weights=weights, k=1)[0]
return proxy, current_index
rotator = ProxyRotator(
["http://proxy1.example:8080", "http://proxy2.example:8080", "http://proxy3.example:8080"],
strategy=random_strategy,
)Strategi acak menyebar beban tidak berurutan, sedangkan strategi berbobot cocok kalau sebagian proxy lebih cepat atau lebih murah. Gabungkan juga dengan logika geo: proxy khusus lokasi tertentu untuk konten yang hanya muncul di region tertentu.
Kadang satu request butuh proxy khusus — misalnya halaman yang hanya tampil untuk IP Indonesia. Override rotator cukup dengan argumen proxy di request itu, misalnya response.follow(url, callback=self.parse, proxy="http://geo-proxy.example:8080").
Untuk menangani blokir, spider punya sistem deteksi bawaan. Status seperti 403, 429, dan 503 dianggap blokir, lalu request di-retry dengan proxy berikutnya dari rotator — hingga max_blocked_retries kali (default 3). Logika deteksinya bisa diperluas dengan menimpa is_blocked:
from scrapling.spiders import Spider, Response
class KatalogSpider(Spider):
name = "katalog"
start_urls = ["https://example.com/products"]
max_blocked_retries = 5
async def is_blocked(self, response: Response) -> bool:
if response.status in {403, 429, 503}:
return True
body = response.body.decode("utf-8", errors="ignore")
return "access denied" in body.lower()
async def retry_blocked_request(self, request, response):
request.sid = "stealth"
return requestKombinasi ini menghasilkan siklus yang tangguh: request gagal karena IP kena limit, is_blocked mengenalinya, rotator memberi proxy baru, dan retry berjalan dengan IP segar.
Proxy mengubah IP, tapi server tetap bisa menebak kalian bot dari pola request-nya. Parameter impersonate menyamarkan TLS fingerprint, header order, dan HTTP/2 settings ke profil browser tertentu. Jika dilewatkan daftar, Scrapling memilih salah satu secara acak per request — pola yang sulit dikenali:
from scrapling import Fetcher
page = Fetcher.get(
"https://example.com",
impersonate=["chrome", "firefox", "safari"],
stealthy_headers=True,
)stealthy_headers=True membuat header request dibuat ulang agar konsisten dengan versi browser yang diimpersonate — termasuk urutan header, bukan sekadar User-Agent. Di episode 13 kalian akan membedah bagaimana fingerprint TLS ini bekerja di level protocol.
Kalian sekarang punya arsenal untuk bertahan di medan yang tidak ramah: paham jenis proxy dan kapan memakainya, merotasi IP otomatis dengan ProxyRotator plus strategi kustom, melacak proxy terpakai lewat metadata respons, meng-override proxy per request, dan menambal sistem deteksi blokir bawaan spider. Ditambah spoofing header dan TLS fingerprint, request kalian sekarang tampil seperti kunjungan pengguna biasa, bukan bot.
Inti yang harus dibawa pulang:
ProxyRotator memberi rotasi cyclic yang thread-safe untuk semua jenis session.is_blocked, max_blocked_retries, dan retry_blocked_request untuk retry otomatis dengan proxy segar.impersonate dan stealthy_headers agar request tidak dikenali dari pola header dan TLS.Di episode 13 kita turun ke level protocol: networking dan TLS impersonation. Kalian akan membedah bagaimana JA3/JA4 fingerprint dibentuk, kenapa HTTP/2 settings ikut membocorkan identitas, dan bagaimana curl_cffi di balik Scrapling membuat request kalian tidak bisa dibedakan dari browser sungguhan.