Proxy Rotasi untuk Web Scraping: Python requests, Scrapy Middleware, dan Pelacakan Peringkat
Panduan praktis untuk merotasi proxy di Python dan Scrapy - pemilihan pool, sesi sticky versus rotasi per-request, kode middleware yang berfungsi, deteksi blokir, dan mengapa rank tracker membutuhkan konsistensi lokasi lebih dari sekadar volume IP mentah.
Jika Anda melakukan scrape beberapa ratus halaman dari satu IP, Anda pada akhirnya akan menemui rate limit, CAPTCHA, atau soft block. Rotasi adalah solusi standar - tetapi rotasi yang buruk lebih buruk daripada tidak sama sekali: itu membakar anggaran proxy, membuat debugging lebih sulit, dan bisa terlihat bahkan lebih seperti bot daripada crawler yang stabil dan sopan.
Panduan ini membahas cara kerja rotasi, cara mengimplementasikannya di Python dengan requests dan di Scrapy dengan downloader middleware, dan bagaimana teknik yang sama berlaku untuk pelacakan peringkat SERP.
Sebelum Anda merotasi, periksa apakah rotasi adalah masalahnya
Rotasi menyembunyikan blokir di tingkat IP. Ini tidak memperbaiki:
- Masalah pola. Berapa pun jumlah IP tidak akan menyelamatkan crawler yang meminta URL yang sama lima puluh kali per detik dengan user agent default.
- Masalah sesi. Jika alur Anda mengharuskan tetap login, IP baru di tengah sesi terlihat seperti pencurian akun.
- Masalah geo. Jika konten yang Anda butuhkan terkunci secara regional, Anda memerlukan negara yang tepat, bukan lebih banyak IP.
Diagnosis dulu: catat kode status, isi respons, dan waktu respons per IP. Jika setiap IP mendapatkan 200 dan satu halaman tertentu mengembalikan blokir, masalah Anda adalah perilaku permintaan, bukan reputasi IP.
Pilih jenis proxy yang cocok dengan pekerjaan
| Tipe | Kekuatan umum | Perhatikan |
|---|---|---|
| Datacenter | Cepat, konkurensi tinggi, tersedia luas | Mudah diidentifikasi; diblokir oleh situs ketat |
| Residensial | Menyatu dengan lalu lintas pengguna nyata | Lebih lambat; batas bandwidth; penanganan sesi penting |
| Mobile | Kepercayaan tinggi, paling sulit diblokir | Mahal; tidak stabil; sesi bersamaan lebih sedikit |
| ISP / residensial statis | IP stabil dan konsisten | Pool lebih kecil; rotasi lebih sedikit |
Untuk data terstruktur di situs yang permisif, datacenter biasanya cukup. Untuk hasil pencarian, marketplace, dan situs travel, residensial atau mobile biasanya diperlukan. Evaluasi penyedia berdasarkan granularitas rotasi, kontrol sesi, cakupan geo, dan cara penanganan blokir - bukan berdasarkan jumlah IP yang ditonjolkan.
Strategi rotasi
Rotasi per-request
Setiap permintaan keluar dari IP yang dipilih oleh pool. Banyak penyedia menawarkan ini sebagai satu hostname gateway rotasi ditambah port, atau sebagai token sesi di username. Terbaik untuk pengambilan halaman tanpa status.
Sesi sticky
IP yang sama digunakan kembali untuk jendela tertentu atau sampai Anda melepaskannya. Gunakan ini untuk alur multi-langkah: pencarian, buka listing, baca halaman detail. Di sebagian besar pool komersial, stickiness dikendalikan oleh pengenal sesi di username proxy, dan pengenal baru menghasilkan IP baru.
Stickiness geografis
Untuk pelacakan peringkat dan pengecekan harga, Anda biasanya menginginkan kota atau negara yang sama di seluruh set kueri, karena hasil bervariasi menurut lokasi. Rotasi di dalam satu geo, bukan antar-geo.
Pembatasan konkurensi
Rotasi dan rate limiting saling melengkapi, bukan pengganti. Crawler dengan lima permintaan bersamaan yang mematuhi Retry-After akan mengalahkan crawler dengan dua ratus thread yang menghantam setiap IP sampai diblokir.
Python: merotasi proxy dengan requests
Pasang dukungan SOCKS jika Anda memerlukannya. Library requests menggunakan PySocks di bawahnya:
pip install "requests[socks]"
Lalu rotasi di seluruh pool:
import itertools
import requests
POOL = [
'http://user:[email protected]:8000',
'http://user:[email protected]:8000',
'socks5h://user:[email protected]:1080',
]
proxy_cycle = itertools.cycle(POOL)
def fetch(url, timeout=20):
proxy = next(proxy_cycle)
proxies = {'http': proxy, 'https': proxy}
response = requests.get(url, proxies=proxies, timeout=timeout)
response.raise_for_status()
return response.text
Beberapa hal yang layak ditambahkan di produksi:
- Coba ulang dengan proxy yang berbeda pada
429atau403, bukan proxy yang sama. - Gunakan
requests.Session()untuk penggunaan ulang koneksi, tetapi buat satu sesi per IP alih-alih satu sesi untuk seluruh crawl. - Catat proxy mana yang menghasilkan hasil mana sehingga Anda dapat membuang IP buruk alih-alih mengundinya lagi.
- Gunakan
socks5h://(perhatikanh) saat Anda ingin nama host diselesaikan di proxy, bukan secara lokal.
Scrapy: middleware downloader proxy rotasi
Scrapy sudah menangani autentikasi proxy melalui middleware proxy HTTP bawaan, jadi Anda hanya perlu menyetel request.meta['proxy'] sebelum permintaan dikirim. Middleware rotasi sederhana terlihat seperti ini:
import random
class RotatingProxyMiddleware:
def __init__(self, proxies):
self.proxies = proxies
@classmethod
def from_crawler(cls, crawler):
proxies = crawler.settings.getlist('ROTATING_PROXIES')
if not proxies:
raise ValueError('ROTATING_PROXIES is empty')
return cls(proxies)
def process_request(self, request, spider):
request.meta['proxy'] = random.choice(self.proxies)
Daftarkan di modul pengaturan Anda:
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.RotatingProxyMiddleware': 350,
}
ROTATING_PROXIES = [
'http://user:[email protected]:8000',
'http://user:[email protected]:8000',
]
AUTOTHROTTLE_ENABLED = True
RETRY_HTTP_CODES = [403, 429, 500, 502, 503, 504]
Dua catatan:
random.choiceyang naif akan terus menggunakan kembali IP yang diblokir. Proyek komunitas sepertiscrapy-rotating-proxiesmenambahkan deteksi blokir dan statistik per-proxy di atas ide yang sama, yang sepadan dengan dependensinya setelah Anda meningkatkan skala melewati beberapa permintaan.- Middleware retry Scrapy biasanya mencoba ulang dengan proxy yang sama. Jika blokir adalah masalah Anda, buat jalur retry menjalankan ulang pemilihan proxy.
Menerapkan pendekatan yang sama untuk pelacakan peringkat
Rank tracker memiliki persyaratan proxy yang tidak dimiliki scraper generik: konsistensi lokasi. Kata kunci yang diperiksa dari satu kota lalu dari kota lain akan menghasilkan SERP yang berbeda dan grafik pergerakan yang tidak berarti.
Aturan praktis untuk pelacakan peringkat:
- Pilih satu lokasi per kata kunci yang dilacak dan jaga stabilitasnya di seluruh eksekusi.
- Segarkan IP secara berkala agar tidak ditandai, tetapi tetap di dalam kota atau wilayah yang sama.
- Gunakan proxy mobile saat melacak hasil mobile, karena SERP desktop dan mobile cukup berbeda sehingga berpengaruh.
- Cache secara agresif dan periksa sesuai jadwal, bukan terus-menerus.
Juga perlu dinyatakan secara gamblang: scraping mesin pencari biasanya melanggar ketentuan layanan mereka. Jika Anda membutuhkan data peringkat yang andal, API resmi dan feed pelacakan peringkat berlisensi adalah jalur yang lebih rendah risiko. Proxy adalah untuk kasus di mana API benar-benar tidak ada.
Cara mengetahui apakah rotasi berhasil
Lacak ini selama satu crawl penuh, bukan per permintaan:
- Tingkat keberhasilan per proxy, yaitu respons 2xx dibagi dengan percobaan.
- Tingkat blokir per proxy, dengan jenis blokir yang dicatat:
403, CAPTCHA, isi kosong, halaman consent. - Waktu respons median per proxy. Proxy yang berfungsi tetapi membutuhkan tiga puluh detik per halaman adalah kerugian bersih.
- IP unik yang benar-benar digunakan, dibandingkan dengan ukuran pool yang Anda konfigurasi.
Jika tingkat keberhasilan datar di semua IP, masalah Anda bukan reputasi IP, dan berapa pun rotasi tidak akan membantu.
Intinya
Rotasi hanya setelah Anda memperbaiki laju permintaan, header, dan logika sesi. Gunakan rotasi per-request untuk pengambilan tanpa status dan sesi sticky untuk apa pun yang multi-langkah. Di Python, requests memerlukan ekstra SOCKS dan proxy per sesi, sedangkan di Scrapy middleware downloader yang menetapkan request.meta['proxy'] akan membawa Anda sebagian besar jalan, dengan paket pelacakan blokir menangani sisanya. Dan untuk pelacakan peringkat, perlakukan geografi sebagai persyaratan dan rotasi sebagai pemeliharaan.