ProxyScrape Web Scraping dengan Playwright: Mengarahkan Chromium Headless Melalui Proxy HTTP dan SOCKS5
Konfigurasikan Playwright agar Chromium headless keluar melalui ProxyScrape, verifikasi IP keluar sebelum scraping, rotasi endpoint HTTP atau SOCKS5 per konteks browser, dan klasifikasikan error proxy dengan benar.
Ikhtisar
Browser headless menempatkan konfigurasi proxy di dalam browser, bukan di dalam pustaka HTTP Anda. Itu mengubah penyiapan: Anda mengonfigurasi proxy saat meluncurkan browser atau membuat konteks browser, Anda harus menangani autentikasi proxy, dan konfigurasi per konteks adalah yang memungkinkan rotasi tanpa memulai ulang Chromium untuk setiap permintaan.
Tutorial ini menggunakan Playwright dengan Chromium dan endpoint ProxyScrape (HTTP atau SOCKS5). Ini mencakup peluncuran satu endpoint, pemeriksaan IP keluar, rotasi per konteks di beberapa endpoint, penanganan error proxy, dan menjalankannya di CI Linux tanpa menghabiskan memori.
Kapan browser headless adalah alat yang tepat
- Target merender konten di sisi klien, sehingga permintaan HTTP biasa mengembalikan shell kosong.
- Anda perlu berinteraksi: mengisi formulir, mengeklik, menggulir, atau menunggu jaringan idle.
- Anda memerlukan perilaku tingkat browser seperti cookie,
localStorage, atau service worker. - Anda memvalidasi bagaimana situs berperilaku untuk wilayah tertentu.
Tetap gunakan klien HTTP biasa saat halaman dirender server; itu jauh lebih murah dan cepat.
Prasyarat
- Node.js 18 atau lebih baru dan npm.
- Playwright terinstal dengan Chromium.
- Kredensial ProxyScrape plus host dan port untuk
httpdan/atausocks5. Proxy residensial, datacenter, dan mobile semuanya berfungsi di sini; pilih jenis yang cocok dengan pertahanan target. - Linux, macOS, atau Windows. Catatan CI mengasumsikan runner Debian atau Ubuntu.
Langkah-langkah
Langkah 1 — Instal Playwright dan Chromium
mkdir proxyscrape-playwright
cd proxyscrape-playwright
npm init -y
npm install playwright
npx playwright install --with-deps chromium
--with-deps menginstal pustaka OS yang dibutuhkan Chromium pada image Linux dan runner CI.
Langkah 2 — Tentukan apakah proxy berlaku untuk browser atau konteks
| Cakupan | Di mana diatur | Gunakan untuk | Peringatan |
|---|---|---|---|
| Browser | chromium.launch({ proxy }) |
Satu endpoint untuk seluruh proses | Setiap konteks berbagi satu IP keluar |
| Konteks | browser.newContext({ proxy }) |
Rotasi: satu endpoint per konteks, secara paralel | Dukungan mesin berbeda; Chromium adalah default yang aman — konfirmasi dukungan proxy per konteks untuk versi Playwright Anda sebelum mengandalkannya di Firefox atau WebKit |
Dua aturan praktis:
- Berikan kredensial sebagai bidang
usernamedanpasswordterpisah. Chromium mengabaikan kredensial yang disematkan di URL server proxy. - Nilai
servermenerima skema:http://host:portuntuk endpoint HTTP ProxyScrape dansocks5://host:portuntuk SOCKS5.
Langkah 3 — Luncurkan melalui satu endpoint dan periksa IP keluar
// launch-proxy.mjs
import { chromium } from 'playwright';
const proxy = {
server: process.env.PROXYSCRAPE_SERVER, // http://HOST:PORT or socks5://HOST:PORT
username: process.env.PROXYSCRAPE_USERNAME,
password: process.env.PROXYSCRAPE_PASSWORD,
};
const browser = await chromium.launch({ proxy, headless: true });
try {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://api.ipify.org?format=json', { waitUntil: 'domcontentloaded' });
console.log('exit ip:', await page.textContent('body'));
} finally {
await browser.close();
}
export PROXYSCRAPE_SERVER="http://host-from-your-plan:port-from-your-plan"
export PROXYSCRAPE_USERNAME="your-username"
export PROXYSCRAPE_PASSWORD="your-password"
node launch-proxy.mjs
Jika ini mencetak IP, jalur proxy berfungsi dari ujung ke ujung. Jika macet atau melempar error, langsung ke tabel pemecahan masalah sebelum menulis kode lebih banyak.
Langkah 4 — Gagal cepat saat lalu lintas tidak melalui proxy
Konfigurasi yang salah secara diam-diam — misalnya, salah ketik pada string server — dapat membuat Anda scraping dari IP Anda sendiri. Catat IP langsung Anda sekali, lalu lakukan assert terhadapnya.
// exit-ip.mjs
export async function getExitIp(page) {
await page.goto('https://api.ipify.org?format=json', { waitUntil: 'domcontentloaded' });
const body = await page.textContent('body');
return JSON.parse(body).ip;
}
export function assertProxied(exitIp, directIp) {
if (directIp && exitIp === directIp) {
throw new Error(`Traffic was not proxied: exit IP ${exitIp} equals the direct IP`);
}
}
Prosedur berurutan:
- Jalankan skrip sekali pakai tanpa proxy dikonfigurasi dan catat hasilnya sebagai
DIRECT_IP. - Jalankan lagi skrip yang menggunakan proxy.
- Panggil
assertProxied(exitIp, process.env.DIRECT_IP)sebelum scraping nyata apa pun, dan gagalkan proses saat assertion terpicu.
Langkah 5 — Rotasi endpoint di seluruh konteks browser
Satu browser, banyak konteks, masing-masing satu endpoint.
// rotate-contexts.mjs
import { chromium } from 'playwright';
const ENDPOINTS = (process.env.PROXYSCRAPE_ENDPOINTS ?? '')
.split(',')
.map((entry) => entry.trim())
.filter(Boolean)
.map((entry) => {
const [scheme, host, port, username, password] = entry.split('|');
return { server: `${scheme}://${host}:${port}`, username, password };
});
if (ENDPOINTS.length === 0) {
throw new Error('Set PROXYSCRAPE_ENDPOINTS to http|HOST|PORT|USER|PASS,socks5|HOST|PORT|USER|PASS');
}
const TARGETS = (process.env.TARGETS ?? 'https://example.com,https://example.org').split(',');
const CONCURRENCY = Number(process.env.CONCURRENCY ?? 3);
const USER_AGENT =
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36';
function isProxyError(error) {
const message = String(error && error.message ? error.message : '');
return /ERR_PROXY|ERR_TUNNEL|ERR_PROXY_AUTH/i.test(message);
}
async function runBatch(browser, proxy, urls) {
const context = await browser.newContext({ proxy, userAgent: USER_AGENT });
context.setDefaultTimeout(30000);
const results = [];
try {
const page = await context.newPage();
for (const url of urls) {
try {
const response = await page.goto(url, { waitUntil: 'domcontentloaded' });
results.push({ url, endpoint: proxy.server, status: response ? response.status() : null });
} catch (error) {
results.push({
url,
endpoint: proxy.server,
error: isProxyError(error) ? `proxy: ${error.message}` : error.message,
});
}
}
} finally {
await context.close();
}
return results;
}
const browser = await chromium.launch({ headless: true });
try {
const queue = ENDPOINTS.map((proxy, index) => ({
proxy,
urls: TARGETS.filter((_, targetIndex) => targetIndex % ENDPOINTS.length === index),
}));
const workers = Array.from({ length: Math.min(CONCURRENCY, queue.length) }, async () => {
const collected = [];
while (queue.length > 0) {
const job = queue.shift();
collected.push(...(await runBatch(browser, job.proxy, job.urls)));
}
return collected;
});
const results = (await Promise.all(workers)).flat();
for (const result of results) {
console.log(JSON.stringify(result));
}
} finally {
await browser.close();
}
export PROXYSCRAPE_ENDPOINTS="http|HOST|PORT|USER|PASS,socks5|HOST|PORT|USER|PASS"
export TARGETS="https://example.com,https://example.org,https://example.net"
export CONCURRENCY=3
node rotate-contexts.mjs
Mengapa bentuk ini berhasil:
- Browser dimulai sekali; konteks itu murah dan masing-masing membawa endpoint-nya sendiri.
- Kumpulan worker membatasi berapa banyak konteks yang ada pada saat yang sama, yang merupakan tuas memori utama di Playwright.
- Setiap hasil mencatat endpoint yang melayaninya, sehingga kegagalan dapat dikaitkan tanpa menebak.
Langkah 6 — Perlakukan kegagalan proxy sebagai kegagalan endpoint, bukan kegagalan halaman
net::ERR_PROXY_CONNECTION_FAILED— host atau port proxy salah atau tidak dapat dijangkau.net::ERR_TUNNEL_CONNECTION_FAILED— tunnel CONNECT ke target HTTPS ditolak; pastikan protokol yang Anda konfigurasikan cocok dengan endpoint.net::ERR_PROXY_AUTH_REQUESTED— kredensial ditolak; periksa ulang username dan password, dan berikan sebagai field, bukan di dalam URL server.TimeoutError— endpoint lambat atau target berat; naikkan timeout dan turunkan konkurensi.
Ketika salah satu dari ini muncul, hapus endpoint tersebut dari antrean selama sisa proses dan lanjutkan dengan yang lain. Mencoba ulang endpoint rusak yang sama berulang kali hanya membuang waktu.
Langkah 7 — Jalankan di CI Linux tanpa menghabiskan sumber daya
- Instal dependensi browser di pipeline dengan
npx playwright install --with-deps chromium. - Jaga konkurensi pada dua atau tiga konteks per vCPU di runner CI; setiap konteks membawa halaman yang dirender.
- Luncurkan browser sekali per proses dan tutup konteks di blok
finally. - Utamakan proxy datacenter untuk target bervolume tinggi dengan pertahanan rendah pada tugas terjadwal, dan simpan endpoint residensial atau mobile untuk target yang lebih sulit.
- Perhatikan ekonomi unit: penagihan bayar sesuai pemakaian membuat proses CI yang meledak-ledak mudah dimulai, sementara paket bulanan tetap biasanya lebih murah untuk tugas malam yang tetap.
Pemecahan Masalah
| Gejala | Kemungkinan penyebab | Perbaikan |
|---|---|---|
| Halaman dimuat, tetapi dari IP Anda sendiri | Proxy diabaikan (salah ketik di server, atau opsinya tidak diteruskan ke konteks) |
Catat IP keluar dengan helper Langkah 4 dan naikkan error saat cocok dengan IP langsung |
ERR_PROXY_CONNECTION_FAILED |
Host atau port salah, atau egress CI diblokir | Uji endpoint yang sama dengan curl, lalu periksa kebijakan jaringan |
ERR_PROXY_AUTH_REQUESTED |
Kredensial salah, atau disematkan di URL | Berikan field username dan password, jangan pernah user:pass@host |
ERR_TUNNEL_CONNECTION_FAILED pada HTTPS |
Ketidakcocokan protokol antara endpoint dan skema yang Anda konfigurasikan | Coba endpoint HTTP, lalu endpoint SOCKS5, dan simpan yang berfungsi |
| Setiap konteks melaporkan IP keluar yang sama | Proxy tingkat browser digunakan, bukan tingkat konteks, atau mesin tidak mendukung proxy per konteks | Gunakan chromium.launch() dan atur proxy pada setiap newContext() |
| Proses mematikan runner CI | Terlalu banyak konteks bersamaan | Turunkan CONCURRENCY ke 2 dan ukur ulang memori |
Ringkasan
- Di Playwright, proxy dimiliki oleh panggilan peluncuran atau konteks browser, bukan oleh permintaan individual.
- Verifikasi IP keluar sebelum scraping; proxy yang salah konfigurasi dapat diam-diam meninggalkan Anda di IP Anda sendiri.
- Rotasi dengan memberi setiap konteks endpoint ProxyScrape HTTP atau SOCKS5-nya sendiri dan membatasi berapa banyak konteks yang berjalan sekaligus.
- Klasifikasikan kegagalan
ERR_PROXY*danERR_TUNNEL*sebagai masalah endpoint, hapus endpoint tersebut, dan biarkan proses tetap berjalan.