Proxy Rotasi Selenium di Python: ChromeOptions, Autentikasi, dan Rotasi Per-Sesi
Selenium mengikat proxy ke peluncuran browser, bukan ke permintaan — yang membuat rotasi menjadi canggung dan rotasi terautentikasi menjadi canggung dengan cara berbeda. Berikut tiga pendekatan yang benar-benar berfungsi di Selenium 4, dengan kode Python untuk ChromeOptions, sebuah a
Selenium tidak memiliki konsep proxy rotasi. Sesi browser dan IP keluar terikat bersama saat peluncuran: Anda meneruskan --proxy-server= ke ChromeOptions, driver dimulai, dan setiap permintaan yang dibuat browser melewati endpoint tersebut sampai Anda menutupnya.
Fakta desain tunggal itu menjelaskan mengapa pencarian untuk selenium rotating proxy mengembalikan begitu banyak saran yang kontradiktif. Beberapa panduan meluncurkan ulang browser sekali per proxy. Yang lain menggunakan pustaka wrapper. Keduanya berfungsi — tetapi gagal di tempat yang berbeda, dan hal yang membuat sebagian besar percobaan pertama gagal adalah autentikasi, bukan rotasi itu sendiri.
Panduan ini membahas mekanisme sebagaimana berlaku untuk Chrome dan Chromium yang dikendalikan oleh Selenium 4 di Python: apa yang sebenarnya diterima oleh flag proxy, tiga cara rotasi yang dapat dilakukan, cara memverifikasi IP keluar, dan jebakan yang paling banyak menghabiskan waktu.
Mengapa rotasi Selenium berbeda dari requests, httpx, atau Scrapy
requestsdanhttpxmenerima proxy sebagai argumen per panggilan. Rotasi hanyalah perubahan dictionary.- Scrapy dapat menukar proxy antar permintaan di middleware downloader, tanpa memulai ulang sesi.
- Selenium menetapkan proxy pada proses browser. Tidak ada argumen proxy per permintaan yang didukung, jadi rotasi di tengah sesi memerlukan lapisan intersepsi seperti selenium-wire, atau pekerjaan DevTools Protocol.
Kendala kedua adalah flag milik Chrome sendiri. --proxy-server=socks5://host:port menerima skema, host, dan port — tidak ada yang lain. Tidak ada field kredensial. Jika proxy menuntut autentikasi, Chrome memunculkan dialog autentikasi HTTP yang tidak dapat diisi oleh Selenium dan yang tidak pernah dirender sama sekali oleh mode headless. Beberapa endpoint SOCKS5 juga menolak koneksi tanpa kredensial yang tidak dapat dibawa oleh flag tersebut.
Jadi sebenarnya ada dua masalah yang harus diselesaikan secara terpisah: rotasi IP keluar, dan memberikan kredensial ke proxy.
Tiga pendekatan, dibandingkan
| Pendekatan | Granularitas rotasi | Menangani kredensial | Di mana menyakitkan |
|---|---|---|---|
| Luncurkan ulang driver per proxy | Per sesi browser | Tidak — pasangkan dengan allowlist IP | Setiap rotasi membutuhkan biaya memulai browser |
Ekstensi autentikasi melalui --load-extension |
Per sesi browser | Ya | Pemasangan ekstensi dan keanehan headless |
| selenium-wire | Per permintaan | Ya | Dependensi tambahan plus lapisan intersepsi lokal |
Sebagian besar otomatisasi browser tidak memerlukan rotasi per permintaan. Jika alur kerja Anda adalah buka halaman, tunggu JavaScript, ekstrak, lanjut, rotasi per sesi biasanya cukup dan jauh lebih mudah di-debug.
Pendekatan 1: luncurkan ulang driver per proxy
Ini adalah opsi yang paling tidak ajaib dan paling mudah dicerna di produksi.
import random
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
# Documentation ranges from RFC 5737 - replace with your own endpoints.
PROXIES = [
'http://198.51.100.10:8080',
'http://198.51.100.11:8080',
'socks5://203.0.113.7:1080',
]
def build_driver(proxy_url: str) -> webdriver.Chrome:
options = Options()
options.add_argument(f'--proxy-server={proxy_url}')
options.add_argument('--headless=new')
options.add_argument('--disable-dev-shm-usage')
return webdriver.Chrome(options=options)
def exit_ip(driver: webdriver.Chrome) -> str:
driver.get('https://api.ipify.org')
return driver.find_element(By.TAG_NAME, 'body').text.strip()
for proxy in random.sample(PROXIES, len(PROXIES)):
driver = build_driver(proxy)
try:
print(f'{proxy} -> {exit_ip(driver)}')
finally:
driver.quit()
Tiga kebiasaan membedakan skrip yang berfungsi dari skrip yang misterius mati semalam:
- Selalu quit di blok
finally. Proses chromedriver yatim menahan memori dan lock file. - Beri setiap worker paralel direktori profilnya sendiri dengan
--user-data-dir=/tmp/chrome-worker-1. Dua instans Chrome yang berbagi profil akan bersaing untuk lock. - Gunakan
--no-sandboxhanya di container yang Anda kendalikan, jangan pernah di sesi desktop normal.
Pendekatan ini bekerja dengan bersih untuk proxy tanpa autentikasi, dan di sinilah allowlist IP berperan.
Pendekatan 2: memberikan kredensial ke browser
Opsi A: allowlist IP egress Anda sendiri
Banyak penyedia mengizinkan Anda mengotorisasi IP asal yang Anda gunakan, dan pada titik itu proxy menerima Anda tanpa username atau password dan Pendekatan 1 berfungsi tanpa perubahan. Dua catatan: IP egress Anda harus stabil, yang canggung di CI atau pada koneksi rumah yang tersambung ulang, dan IP yang di-allowlist adalah otorisasi tetap yang harus Anda ingat untuk mencabutnya.
Opsi B: ekstensi yang menjawab prompt autentikasi
Ekstensi Chrome dapat menyediakan kredensial proxy melalui chrome.webRequest.onAuthRequired. Pasangan Manifest V3 minimal terlihat seperti ini.
{
"manifest_version": 3,
"name": "proxy-auth",
"version": "1.0",
"permissions": ["webRequest", "webRequestAuthProvider"],
"host_permissions": ["<all_urls>"],
"background": { "service_worker": "background.js" }
}
chrome.webRequest.onAuthRequired.addListener(
(details, callback) => {
callback({ authCredentials: { username: 'USER', password: 'PASS' } });
},
{ urls: ['<all_urls>'] },
['asyncBlocking']
);
Muat saat driver dimulai:
options.add_argument('--disable-extensions-except=/opt/proxy-auth')
options.add_argument('--load-extension=/opt/proxy-auth')
Dua hal yang perlu diketahui sebelum Anda membangun di atas ini. Penanganan callback autentikasi telah berubah di berbagai rilis Chrome; jika bentuk callback ditolak, kembalikan objek kredensial dari listener alih-alih memanggil callback(). Dan pemuatan ekstensi dalam mode headless adalah bagian yang paling mungkin mengejutkan Anda — gunakan --headless=new alih-alih mode headless lama.
Opsi C: selenium-wire
Jika Anda benar-benar memerlukan rotasi per permintaan atau di tengah sesi, selenium-wire menempatkan proxy lokal kecil di depan browser dan memungkinkan Anda mengatur proxy upstream di Python.
from selenium.webdriver.common.by import By
from seleniumwire import webdriver
proxy = 'http://USER:[email protected]:8080'
wire_options = {
'proxy': {
'http': proxy,
'https': proxy,
'no_proxy': 'localhost,127.0.0.1',
}
}
driver = webdriver.Chrome(seleniumwire_options=wire_options)
try:
driver.get('https://api.ipify.org')
print(driver.find_element(By.TAG_NAME, 'body').text)
finally:
driver.quit()
Karena ada lapisan intersepsi lokal yang terlibat, pin versi selenium-wire dan Selenium bersama-sama dan uji ulang setelah salah satunya di-upgrade.
Apakah Anda perlu SOCKS5 khusus untuk Selenium?
Biasanya tidak, tetapi ini didukung. Chrome menerima socks5://host:port di --proxy-server, dan SOCKS5 menyerahkan lalu lintas di lapisan socket, yang berguna ketika pool Anda hanya SOCKS. Batasan kredensialnya identik: flag tidak memiliki tempat untuk menaruh username, jadi Anda kembali ke allowlist atau ekstensi.
Sebuah klarifikasi yang penting untuk verifikasi: merutekan browser melalui SOCKS5 mengendalikan lalu lintas TCP. Itu tidak, dengan sendirinya, menghentikan WebRTC membuka jalur UDP tanpa proxy. Lihat checklist di bawah.
Memilih strategi rotasi untuk otomatisasi browser
| Strategi | Pemicu rotasi | Cocok untuk | Trade-off |
|---|---|---|---|
| Sesi sticky per tugas | Saat tugas dimulai | Login, alur multi-langkah, daftar berhalaman | Satu IP menyerap seluruh tugas |
| Per N halaman atau per jendela waktu | Penghitung atau pengatur waktu | Crawling luas, halaman daftar | Rotasi di tengah alur dapat merusak state |
| Per sesi browser | Setiap peluncuran driver | Pekerjaan scraping dan screenshot yang sederhana | Biaya peluncuran mendominasi runtime |
| Satu proxy per worker | Saat worker dimulai | Crawling paralel | Beban per IP perlu dilacak |
Karena sesi browser mahal, rotasi per permintaan biasanya adalah default yang salah untuk Selenium — Anda membayar restart proses untuk setiap URL. Konsistensi lokasi juga lebih penting daripada volume IP mentah untuk hasil yang bergantung pada lokasi. Jika Anda mengambil sampel halaman, toko, atau harga yang dilokalkan untuk pasar tertentu, pertahankan region keluar tetap untuk seluruh sesi, atau angka yang Anda kumpulkan tidak akan dapat direproduksi pada proses berikutnya.
Memverifikasi IP keluar, DNS, dan WebRTC
Verifikasi bukan opsional untuk proses headless, karena tidak ada jendela untuk dilihat sekilas. Periksa tiga hal.
1. IP keluarnya benar-benar berubah. Gunakan kembali helper exit_ip di atas dan pastikan nilainya berbeda dari alamat Anda sendiri. Bandingkan dengan endpoint echo kedua sesekali agar Anda tidak tertipu oleh respons yang di-cache.
2. Perilaku resolusi DNS. Dengan proxy HTTP, hostname biasanya di-resolve oleh proxy, dan itulah yang Anda inginkan. Penanganan SOCKS5 layak dikonfirmasi daripada diasumsikan: buka halaman uji kebocoran DNS publik dalam proses non-headless dan bandingkan resolver yang ditampilkan dengan milik ISP Anda.
3. WebRTC. Chrome dapat menggunakan jalur UDP tanpa proxy meskipun proxy dikonfigurasi. Flag di bawah memaksa WebRTC untuk menghindari UDP tanpa proxy.
options.add_argument('--force-webrtc-ip-handling-policy=disable_non_proxied_udp')
Terakhir, catat proxy yang digunakan dan IP keluar yang diamati untuk setiap sesi. Ketika halaman mengembalikan tantangan, bahasa yang salah, atau harga yang tidak Anda duga, baris log itu adalah hal pertama yang Anda inginkan.
Jebakan yang paling banyak membuang waktu
- Kebocoran driver. Setiap chromedriver yatim menahan memori. Di dalam container ini biasanya terlihat seperti crash misterius alih-alih kebocoran. Gunakan
try/finallydi mana-mana. - Direktori profil bersama. Instans paralel yang berbagi user data dir saling memblokir. Satu direktori per worker.
- Membaca kegagalan sebagai blokir. 403, respons kosong, dan halaman tantangan adalah tiga masalah berbeda. Catat kode status, judul halaman, dan panjang body sebelum menyalahkan proxy.
- Menggeneralisasi dari satu halaman. Verifikasi IP keluar sebelum mengotomatiskan seratus halaman, bukan setelahnya.
- Melupakan aturan non-teknis. Merotasi IP tidak mengubah apa yang diizinkan oleh ketentuan layanan situs, robots.txt-nya, atau hukum perlindungan data yang berlaku — terutama jika Anda mengumpulkan data pribadi di yurisdiksi GDPR. Perlambat, mundur saat error, dan jaga konkurensi tetap moderat.
Versi singkat
- Selenium mengikat proxy ke peluncuran browser, jadi rotasi berarti restart kecuali Anda menambahkan lapisan intersepsi.
- Flag
--proxy-servermilik Chrome tidak dapat membawa kredensial. Pilih allowlist IP, ekstensi autentikasi, atau selenium-wire. - Utamakan rotasi per sesi atau sticky daripada rotasi per permintaan untuk otomatisasi browser.
- Verifikasi IP keluar di dalam sesi, nonaktifkan UDP WebRTC tanpa proxy, dan catat proxy mana yang melayani permintaan mana.
- Quit driver di
finally, isolasi direktori profil per worker, dan buktikan pengaturan pada satu URL sebelum menskalakannya.