Spider Scrapy kamu bisa melaju mulus di 100 halaman uji, lalu tiba-tiba ambruk saat sudah sampai 10.000 halaman. Itu bukan sekadar bug scraping—biasanya ada masalah jaringan yang menyamar jadi bug scraping. Solusi yang paling sering dipakai adalah proxy, dan menambahkannya ke request.meta cuma butuh sekitar tiga puluh detik.
Masalahnya, perbaikan 30 detik itulah yang sering jadi batas akhir banyak tutorial dasar. Mereka cuma nunjukin meta={"proxy": "http://IP:PORT"}, mungkin ditambah satu class middleware, lalu selesai. Hal-hal penting seperti apa yang terjadi kalau proxy mati di tengah crawl, bagaimana kredensial bisa bocor ke riwayat Git, atau kenapa retry bisa tetap memakai proxy gagal yang sama, sering banget tidak dibahas. Itulah isu produksi yang dicakup panduan ini: konfigurasi fail-closed, pengelolaan secret, pemilihan proxy yang disengaja saat retry, batasan protokol, dan trade-off biaya yang bisa diukur.
Apa Itu Proxy Middleware di Scrapy?
Proxy middleware adalah potongan kode yang duduk di pipeline downloader Scrapy dan menentukan alamat IP mana yang akan terlihat sebagai sumber request sebelum request itu dikirim. Scrapy sudah menyediakan bawaan bernama HttpProxyMiddleware, yang membaca key proxy dari request.meta, menambahkan autentikasi proxy kalau perlu, lalu menyerahkan request ke download handler yang benar-benar membuka koneksi. Custom proxy middleware tidak menggantikan langkah transport itu — ia berperan sebagai selector yang menentukan proxy mana yang dipasang sebelum mekanisme bawaan mengambil alih. Perbedaan ini jauh lebih penting daripada kelihatannya, dan sering jadi sumber laporan bug seperti “custom middleware saya tidak jalan”.
Mengapa Proxy Penting untuk Proyek Scrapy Produksi
Proxy mengubah jalur jaringan dan IP sumber yang terlihat. Ini bisa membantu untuk pengujian berbasis lokasi yang sah, mendistribusikan traffic request yang diizinkan, dan mengisolasi kegagalan jaringan. Tapi proxy tidak memberi izin, tidak otomatis melewati rate limit, dan tidak menjamin akses. Apakah sebuah crawl memang butuh proxy atau tidak bergantung pada target, syarat penggunaannya, laju request, dan kebutuhan reliabilitas pekerjaan.
Tidak semua proxy dibuat sama, dan memilih kelas yang salah bisa jadi insiden produksi tersendiri:
| Jenis Proxy | Keandalan | Kecepatan | Risiko Terdeteksi | Biaya Umum |
|---|---|---|---|---|
| Proxy publik gratis | Sangat bervariasi | Bervariasi | Sering tinggi | Gratis, tapi risikonya besar secara keamanan dan operasional |
| Proxy datacenter | Bergantung pada penyedia dan target | Sering cepat | Bergantung pada target | Umumnya ditagih per GB atau per IP |
| Proxy residential | Bergantung pada penyedia dan target | Bervariasi | Bergantung pada target | Umumnya ditagih per GB |
| Proxy ISP | Bergantung pada penyedia dan target | Bervariasi | Bergantung pada target | Tergantung penyedia |
Proxy gratis perlu disorot khusus karena risikonya memang besar. Studi 30 bulan Free Proxies Unmasked melacak lebih dari 640.000 alamat dari 11 penyedia: 34,5% aktif setidaknya sekali, dan 16.923 memanipulasi konten. Temuan ini jadi peringatan keamanan yang kuat untuk daftar publik; ini bukan angka kegagalan yang bisa langsung dipakai ke setiap daftar, pool berbayar, target, atau beban kerja.
Proxy juga tidak otomatis menembus deteksi bot modern. Layanan seperti Cloudflare menilai request memakai puluhan sinyal — fingerprint TLS, konsistensi header, eksekusi JavaScript, pola perilaku — dan IP kamu cuma salah satu input di antaranya. Proxy residential yang bersih pun masih bisa ditandai kalau header tidak konsisten dan cookie jar kosong. Jaga ekspektasi ini sebelum kamu membangun arsitektur cuma berdasarkan “tinggal rotasi IP saja”.
Sebelum Mulai
- Tingkat kesulitan: Menengah
- Waktu yang dibutuhkan: ~30–45 menit untuk setup produksi penuh, ~5 menit untuk tes cepat
- Yang dibutuhkan: Python 3.9+, Scrapy terpasang (panduan ini diuji dengan Scrapy 2.17.0, dirilis Juli 2026), spider yang sudah berjalan dari
scrapy startproject, dan setidaknya satu endpoint proxy (free trial dari penyedia proxy datacenter mana pun cukup untuk testing)
Langkah 1: Uji Proxy dengan Parameter Request Meta
Cara tercepat memastikan proxy bekerja adalah melewati seluruh arsitektur middleware dan mengujinya langsung.
Built-in HttpProxyMiddleware milik Scrapy membaca key proxy langsung dari request.meta dan merutekan request lewat proxy tersebut. Tidak perlu ubah settings, tidak perlu class middleware — cukup satu keyword argument.
import scrapy
class ProxyTestSpider(scrapy.Spider):
name = "proxy_test"
start_urls = ["https://httpbin.org/ip"]
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(
url,
meta={"proxy": "http://203.0.113.10:8080"},
callback=self.parse,
)
def parse(self, response):
self.logger.info(response.text)
Jalankan dengan scrapy runspider proxy_test.py. Kalau proxy berfungsi, httpbin.org/ip akan menampilkan IP proxy, bukan IP kamu sendiri — itu tanda konfirmasinya. Kalau response macet lalu akhirnya melempar error TCP connection timed out, berarti proxy mati atau tidak bisa dijangkau, yang, spoiler, lebih sering terjadi daripada yang vendor proxy mau akui.
Metode ini cocok untuk spider sekali pakai atau tes cepat. Begitu kamu punya lebih dari satu spider, pendekatan ini mulai berantakan karena kamu meng-hardcode string proxy yang sama di lima file berbeda.
Langkah 2: Bangun Custom Proxy Middleware
Untuk apa pun selain satu spider, logika proxy sebaiknya dipusatkan di satu tempat. Buat class ProxyMiddleware di middlewares.py proyek kamu:
from scrapy.exceptions import NotConfigured
class ProxyMiddleware:
def __init__(self, proxy_url):
self.proxy_url = proxy_url
@classmethod
def from_crawler(cls, crawler):
proxy_url = crawler.settings.get("PROXY_URL")
if not proxy_url:
raise NotConfigured("PROXY_URL wajib diisi; direct fallback tanpa sengaja ditolak")
return cls(proxy_url=proxy_url)
def process_request(self, request, spider):
if "proxy" not in request.meta:
request.meta["proxy"] = self.proxy_url
Lalu daftarkan di settings.py:
import os
PROXY_URL = os.environ.get("PROXY_URL")
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.ProxyMiddleware": 350,
}
Perhatikan penggunaan classmethod from_crawler, bukan __init__ biasa. Inilah pola yang memang direkomendasikan Scrapy untuk membaca settings, dan hook yang akan kita pakai lagi di Langkah 4 saat membahas secret. Keuntungannya sederhana: ubah satu setting, semua spider dalam project ikut pakai proxy baru. Kamu tidak perlu lagi mencari-cari IP lama di lima file.
Langkah 3: Pahami Urutan Eksekusi Middleware (Supaya Proxy Tidak Diam-Diam Tidak Berfungsi)
Ini bagian yang sering dilewati dengan kalimat seperti “set saja priority ke 350, percaya deh.” Downloader middleware di Scrapy berjalan dalam urutan yang spesifik dan konsisten. Kalau kamu tidak paham alurnya, setup proxy bisa memunculkan bug yang kelihatannya sama sekali tidak ada hubungannya dengan proxy.
Hook sisi request (process_request) berjalan dalam urutan priority menaik — angka paling kecil duluan. Hook sisi response (process_response, process_exception) berjalan dalam urutan menurun — angka paling besar duluan, lalu mundur ke bawah.
Alur request (menaik):
Spider → [100] RobotsTxt → [300] HttpAuth → [350] YOUR PROXY MIDDLEWARE
→ [500] UserAgent → [550] Retry → [700] Cookies → [750] HttpProxy
→ Downloader
Alur response (menurun):
Downloader → [750] HttpProxy → [700] Cookies → [550] Retry
→ [500] UserAgent → [350] YOUR PROXY MIDDLEWARE → [300] HttpAuth
→ [100] RobotsTxt → Spider
Berikut tabel priority default terbaru untuk middleware bawaan Scrapy (divalidasi terhadap 2.17.0):
| Middleware | Priority Default |
|---|---|
| RobotsTxtMiddleware | 100 |
| HttpAuthMiddleware | 300 |
| DownloadTimeoutMiddleware | 350 |
| DefaultHeadersMiddleware | 400 |
| UserAgentMiddleware | 500 |
| RetryMiddleware | 550 |
| RedirectMiddleware | 600 |
| CookiesMiddleware | 700 |
| HttpProxyMiddleware | 750 |
| DownloaderStats | 850 |
| HttpCacheMiddleware | 900 |
Saat RetryMiddleware menjadwalkan retry, ia menyalin request yang gagal—termasuk metadata-nya—dan request baru itu masuk lagi ke chain downloader middleware. Hubungan selector dengan priority 550 tidak otomatis menjamin rotasi. Rotasi hanya terjadi kalau kode selector mengenali bahwa itu retry dan sengaja menimpa nilai meta["proxy"] yang ikut tersalin. Priority 350 adalah tempat yang nyaman untuk selector karena ia berjalan sebelum langkah transport bawaan di 750, tapi itu bukan mekanisme rotasi itu sendiri.

Kesalahan Umum Saat Menentukan Urutan Middleware
- Menetapkan middleware kamu ke priority yang sama dengan
HttpProxyMiddleware(750): Ini menciptakan race condition di mana urutan pemrosesan request ditentukan oleh ordering dict Scrapy, bukan logika kamu. Gejalanya: perilaku proxy kadang ada, kadang hilang, dan sulit dijelaskan. - Memakai
setdefault()atauif "proxy" not in request.metadi selector yang berotasi: retry yang disalin akan tetap memakai proxy lama. Gejalanya: setiap retry mengulangi rute gagal yang sama. Solusinya: deteksi retry (misalnyaretry_times > 0) dan ganti secara eksplisit nilai proxy yang dimiliki selector. - Menonaktifkan
HttpProxyMiddlewaresepenuhnya: Sebagian tutorial menyarankan kamu men-set"scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": Nonekarena “custom middleware sudah mengurusnya.” Tidak begitu — custom middleware kamu adalah selector, bukan layer transport. Kalau bawaan ini dimatikan, header autentikasi proxy tidak pernah ditambahkan, dan request bisa keluar tanpa autentikasi (atau tidak keluar sama sekali).
Langkah 4: Hentikan Hardcode Kredensial Proxy
Hampir semua tutorial proxy Scrapy yang ada di halaman teratas menulis http://username:password@proxy.example.com:8080 langsung ke file Python. Artinya secret kamu tersimpan selamanya di riwayat Git, muncul di setiap clone, fork, dan log dump kalau ada orang yang ceroboh pakai print().
Secara praktis ada tiga tingkat pendekatan:
| Metode | Keamanan | Fleksibilitas | Paling Cocok Untuk |
|---|---|---|---|
| Hardcode di spider/settings.py | Buruk — secret tersimpan di repo | Rendah | Hanya testing lokal cepat |
Variabel environment http_proxy (native Scrapy) | Lebih baik — keluar dari code | Rendah (satu proxy) | Pipeline CI/CD, Docker |
File .env + python-dotenv + from_crawler | Terbaik — keluar dari code, per environment | Tinggi (banyak proxy, rotasi) | Scraper produksi |
Opsi ketiga layak dibangun dengan benar. Install python-dotenv, buat file .env (dan langsung tambahkan ke .gitignore — saya serius, lakukan ini sekarang):
PROXY_USER=myuser
PROXY_PASSWORD=my$ecret!Pass
PROXY_HOST=proxy.example.com
PROXY_PORT=8080
Muat di bagian atas settings.py:
from dotenv import load_dotenv
import os
load_dotenv()
PROXY_USER = os.getenv("PROXY_USER")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
PROXY_HOST = os.getenv("PROXY_HOST")
PROXY_PORT = os.getenv("PROXY_PORT")
Lalu baca secara aman di middleware menggunakan from_crawler — ini pola yang menyelesaikan kebingungan yang sering muncul di forum, seperti pertanyaan “gimana saya set ini sebelum menjalankan scrapy crawl kalau kredensialnya berubah tiap run?”:
import os
from urllib.parse import quote
class SecureProxyMiddleware:
def __init__(self, user, password, host, port):
self.user = quote(user, safe="")
self.password = quote(password, safe="")
self.host = host
self.port = port
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(
user=settings.get("PROXY_USER"),
password=settings.get("PROXY_PASSWORD"),
host=settings.get("PROXY_HOST"),
port=settings.get("PROXY_PORT"),
)
def process_request(self, request, spider):
proxy_url = f"http://{self.user}:{self.password}@{self.host}:{self.port}"
request.meta["proxy"] = proxy_url
Perhatikan pemanggilan urllib.parse.quote() pada kredensial. Kalau password kamu mengandung @, : atau / (dan generator password memang suka memasukkan karakter ini), parsing URL akan rusak kecuali di-encode dulu dengan percent-encoding. Ini perbaikan satu baris yang bisa menyelamatkan kamu dari satu jam debugging memalukan terhadap error “invalid proxy URL” yang sebenarnya bukan berasal dari proxy yang invalid.
Simpan kredensial di luar log dan uji percent-encoding dengan nilai yang representatif — tapi palsu. Tunneling HTTPS, SOCKS5, dan kredensial non-Latin punya batasan spesifik handler; jangan berasumsi satu pola autentikasi berlaku untuk semuanya tanpa integration test yang jelas.

Langkah 5: Tambahkan Rotasi Proxy
Satu proxy — bahkan yang bagus — kalau dipakai untuk 5.000 request ke situs yang sama, lama-lama akan ditandai. Kamu butuh pool.
Opsi A — bangun sendiri. Ini memang sederhana:
import random
class RotatingProxyMiddleware:
def __init__(self, proxy_pool):
self.proxy_pool = proxy_pool
@classmethod
def from_crawler(cls, crawler):
return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))
def process_request(self, request, spider):
request.meta["proxy"] = random.choice(self.proxy_pool)
Ini cocok untuk penggunaan dasar, tapi sama sekali tidak tahu proxy mana yang benar-benar hidup. Kamu seperti lempar dadu setiap request.
Opsi B — gunakan scrapy-rotating-proxies. Paket pihak ketiga ini menambahkan deteksi ban dan backoff otomatis secara bawaan:
pip install scrapy-rotating-proxies
Saya perlu jujur di sini: rilis terbaru di PyPI adalah versi 0.6.2, bertanggal 2019, dan proyeknya diberi label Alpha. Belum tentu rusak di Scrapy modern, tapi “tidak aktif dipelihara sejak 2019” jelas beda dengan “sudah teruji untuk traffic produksi 2026.” Kunci versi, uji terhadap target kamu sendiri, dan jangan berasumsi ia mendukung endpoint proxy berautentikasi — pada dasarnya tidak sepenuhnya begitu.
Langkah 6: Bangun Proxy Middleware yang Tahan Gangguan (Deteksi Proxy Mati)
Bagian ini hampir selalu dilewati tutorial lain, padahal inilah yang membedakan demo dengan sistem yang tetap hidup saat crawl 6 jam tanpa pengawasan.
| Skenario | Yang ditunjukkan sebagian besar tutorial | Tambahan dari middleware ini |
|---|---|---|
| Proxy mengembalikan 407 | Tidak dibahas | Diperlakukan sebagai kegagalan autentikasi proxy |
| Target mengembalikan 403/429 | Sering digabungkan | Feedback kebijakan/rate limit dipisahkan dari kesehatan proxy |
| Proxy timeout | Tidak dibahas | Threshold timeout yang bisa diatur, penurunan skor kesehatan |
| Semua proxy mati | Tidak dibahas | Fallback yang aman atau crawl dijeda dengan warning tercatat |
| Proxy flapping (intermiten) | Tidak dibahas | Masa cooldown sebelum dimasukkan lagi ke pool |
import time
import random
from scrapy.exceptions import IgnoreRequest
class FaultTolerantProxyMiddleware:
MAX_FAILURES = 3
COOLDOWN_SECONDS = 300
def __init__(self, proxy_pool):
self.pool = {p: {"failures": 0, "banned_until": 0} for p in proxy_pool}
@classmethod
def from_crawler(cls, crawler):
return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))
def _healthy_proxies(self):
now = time.time()
return [p for p, s in self.pool.items() if s["banned_until"] < now]
def process_request(self, request, spider):
healthy = self._healthy_proxies()
if not healthy:
spider.logger.warning("Semua proxy tidak sehat — crawl dijeda")
raise IgnoreRequest("Tidak ada proxy sehat yang tersedia")
request.meta["proxy"] = random.choice(healthy)
def process_response(self, request, response, spider):
proxy = request.meta.get("proxy")
if proxy and response.status == 407:
self._mark_failure(proxy)
return response
def process_exception(self, request, exception, spider):
proxy = request.meta.get("proxy")
if proxy:
self._mark_failure(proxy)
def _mark_failure(self, proxy):
state = self.pool[proxy]
state["failures"] += 1
if state["failures"] >= self.MAX_FAILURES:
state["banned_until"] = time.time() + self.COOLDOWN_SECONDS
state["failures"] = 0
Beberapa catatan dari pengalaman membangun ini: jangan menganggap setiap 403 sebagai bukti proxy-nya mati — RFC 9110 mendefinisikan 403 sebagai “server memahami tetapi menolak,” yang bisa saja berarti header atau sesi kamu terlihat mencurigakan, bukan proxynya. Sebaliknya, 407 berarti proxy secara spesifik menolak autentikasi kamu — sinyalnya lebih kuat dan lebih spesifik. Mencampur dua sinyal ini ke satu bucket adalah cara orang membuang proxy sehat tanpa alasan.
Buat default retry transient Scrapy tetap eksplisit di produksi supaya reviewer bisa melihat kebijakannya:
RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408, 429]
RETRY_TIMES = 2
Itu adalah default Scrapy 2.17. Jangan asal tambahkan 403 atau 407: 403 adalah penolakan target dengan banyak kemungkinan penyebab, sedangkan 407 adalah masalah autentikasi proxy yang tidak akan diperbaiki oleh retry request generik. Kalau kontrak target tertentu memang membenarkan retry status lain, dokumentasikan alasannya dan uji secara terpisah.

Langkah 7: Pola Proxy-on-Retry yang Terukur
Sebagian target yang diizinkan bisa mengembalikan konten valid secara langsung, lalu baru butuh proxy setelah menerima response sementara yang terdokumentasi. Ini bisa mengurangi byte yang diproksikan, tapi tidak ada persentase penghematan universal yang bisa dipertahankan secara teknis, maupun tingkat keberhasilan direct request yang berlaku umum. Ukur workload kamu sendiri sebelum memakai pola ini.
Gunakan helper publik Scrapy get_retry_request() dan batasi eskalasi hanya pada status spesifik target yang sudah kamu klasifikasikan. Contoh ini memperlakukan 429 dan 503 sebagai sinyal tekanan yang bisa di-retry; 403 dan 407 sengaja tidak dimasukkan.
from scrapy.downloadermiddlewares.retry import get_retry_request
class CostAwareEscalationMiddleware:
def process_response(self, request, response, spider):
if response.status not in {429, 503}:
return response
retry = get_retry_request(
request,
spider=spider,
reason=f"proxy_escalation_{response.status}",
max_retry_times=2,
)
if retry is None:
return response
current_tier = request.meta.get("proxy_tier", "direct")
if current_tier == "direct":
retry.meta["proxy"] = spider.settings["DATACENTER_PROXY"]
retry.meta["proxy_tier"] = "datacenter"
elif current_tier == "datacenter":
retry.meta["proxy"] = spider.settings["RESIDENTIAL_PROXY"]
retry.meta["proxy_tier"] = "residential"
else:
return response
return retry
Catat direct valid-content rate, proxied valid-content rate, byte per record sukses, retry per sukses, dan tambahan latensi. Desain direct-first hanya layak kalau akses direct memang diizinkan dan sistem benar-benar fail closed saat proxy dibutuhkan. Penghematan yang valid adalah penurunan terukur pada traffic yang diproksikan — bukan persentase yang diasumsikan.
Kapan Manajemen Proxy DIY Tidak Lagi Layak
Saya ingin jujur, bukan seolah-olah seluruh artikel ini tidak penting: semua di atas adalah engineering yang nyata dan berguna, dan untuk banyak proyek — crawl volume tinggi, pipeline kustom, atau apa pun yang butuh kontrol penuh atas penjadwalan request — itu memang pilihan yang tepat.
Tapi kalau tujuan kamu sebenarnya adalah “mengambil data terstruktur dari halaman ini” bukan “mengoperasikan infrastruktur proxy,” extraction API bisa jadi batas yang lebih masuk akal. Dokumentasi POST /extract milik Thunderbit saat ini menerima URL halaman dan JSON Schema opsional; kalau schema tidak diberikan, layanan bisa membangunnya dari konten halaman. Endpoint ini juga menyediakan mode render none, basic, dan full, beserta kontrol timeout dan waktu tunggu setelah load. Ekstraksi berbasis prompt saja bukan bagian dari permukaan request yang didukung saat ini, jadi bangun integrasi produksi di sekitar kontrak schema yang terdokumentasi. Ini memindahkan antarmuka ekstraksi ke balik satu request; bukan berarti menjanjikan hasil universal untuk semua target anti-bot atau CAPTCHA.
| Faktor | DIY Scrapy + Proxy | Ekstraksi berbasis API (mis. Thunderbit) |
|---|---|---|
| Upaya setup | Tinggi — middleware, rotasi, logika retry | Rendah — satu API call dengan schema |
| Perilaku jaringan/rendering | Kamu mengatur handler, proxy, header, dan delay | Dikendalikan lewat opsi API yang terdokumentasi |
| Pemeliharaan | Kamu menangani selector, kesehatan pool, dan perubahan target | Kamu menangani kualitas schema, validasi, dan perilaku integrasi |
| Model biaya | Biaya proxy + komputasi + waktu engineering | Dokumen saat ini mencantumkan 20 unit per halaman (dicek 2026-08-10) |
| Kontrol | Penuh — pipeline kustom, chain middleware | Terbatas pada kemampuan API |
| Paling cocok untuk | Crawl kompleks, volume tinggi, logika kustom | Ekstraksi terarah, prototyping, enrichment |
Kalau kamu terutama mengekstrak halaman terstruktur untuk daftar prospek, data produk, atau riset, jalankan pilot representatif dengan Thunderbit Chrome Extension atau API, lalu bandingkan record valid, latensi, unit, dan waktu pemeliharaan. Kalau proyek kamu butuh graph crawl kustom dan kontrol pipeline, Scrapy tetap lebih cocok.
Pelajari Lebih Lanjut
Tips & Kesalahan Umum
- Tip: Uji proxy ke
httpbin.org/ipsebelum mengarahkannya ke target asli. Ini cara tercepat memastikan routing berjalan sebelum kamu menambah kompleksitas di atasnya. - Kesalahan: Menaruh proxy di
request.headersalih-alihrequest.meta. Ini bug yang sering banget terjadi karena kelihatannya mirip typo —HttpProxyMiddlewarecuma membacameta["proxy"], dan percobaan berbasis header akan gagal diam-diam tanpa error yang jelas. - Kesalahan: Menganggap konfigurasi proxy HTTP dan HTTPS selalu identik. URL proxy HTTP yang mengarah ke destination HTTPS umumnya berjalan lewat CONNECT tunneling di handler yang kompatibel, tapi memakai skema
https://untuk endpoint proxy itu sendiri adalah konfigurasi yang berbeda dan lebih jarang didukung — jangan disamakan. - Tip: Kalau kamu butuh dukungan SOCKS5, cek dulu kemampuan download handler pada versi Scrapy kamu. Scrapy 2.17 punya
Httpxhandler eksperimental yang menambahkan dukungan SOCKS5 lewathttpx[socks], tapi statusnya masih experimental — jangan jadikan ini dependensi produksi tanpa pengujian sendiri.
Metode Alternatif
Selain scrapy-rotating-proxies, beberapa tim memilih mengalirkan seluruh logika proxy lewat gateway provider — satu URL proxy tempat vendor menangani rotasi, session stickiness, dan geo-targeting di belakang layar. Pendekatan ini mengurangi kode middleware, tapi mengorbankan sedikit kontrol, dan layak dibandingkan biayanya dengan pool yang dikelola sendiri sebelum kamu membangunnya dari nol.
Kesimpulan
Menetapkan proxy di Scrapy cuma butuh satu baris. Tapi supaya setup itu tahan menghadapi crawl produksi sungguhan, kamu perlu kebijakan kegagalan yang jelas, kredensial yang terlindungi, batas handler yang sudah diuji, dan kode selector yang secara sengaja mengganti metadata proxy yang tersalin saat retry. Kalau kamu cuma membawa dua kebiasaan dari artikel ini, jadikan ini: fail closed saat proxy dibutuhkan, dan jangan pernah commit password proxy ke file Python.
FAQ
Bagaimana cara menyiapkan custom proxy di Scrapy dengan autentikasi?
Gunakan format URL protocol://username:password@host:port, tapi percent-encode dulu username dan password dengan urllib.parse.quote() kalau ada karakter khusus. Untuk produksi, baca kredensial lewat classmethod from_crawler yang mengambil dari environment variables, bukan hardcode.
Priority number berapa yang sebaiknya dipakai untuk custom proxy middleware di Scrapy?
350 adalah priority selector yang umum karena berjalan sebelum HttpProxyMiddleware di 750. Namun angka ini tidak menjamin rotasi. Retry baru akan memakai proxy segar hanya kalau selector mengenali request retry yang disalin dan menimpa nilai meta["proxy"] sebelumnya.
Bagaimana cara menangani proxy mati di Scrapy secara otomatis?
Bangun middleware yang melacak jumlah kegagalan per proxy di process_response dan process_exception, menghapus proxy dari pool aktif setelah melewati ambang gagal, lalu menambahkannya lagi setelah masa cooldown, bukan memblokirnya selamanya.
Bisakah saya memakai Scrapy dengan proxy SOCKS5?
Scrapy 2.17 punya dokumentasi dukungan SOCKS5 di HttpxDownloadHandler eksperimental jika httpx[socks] dipasang. Default handler HTTP/1.1 tidak mendukung proxy SOCKS. Pin handler/version dan jalankan integration test sebelum menganggap jalur ini siap produksi.
Seberapa besar penghematan biaya proxy-on-retry yang benar-benar bisa didapat?
Tidak ada persentase universal. Ukur sendiri proporsi request yang secara sah mengembalikan konten valid langsung, byte yang lewat tiap tier proxy, retry per record sukses, dan tambahan latensi. Pengurangan terukur pada byte yang diproksikan adalah penghematan kamu; kalau akses direct-first tidak diizinkan atau tidak valid, jangan pakai pola ini.


