Зачем безголовым браузерам нужны прокси
Безголовые браузеры — экземпляры браузера без видимого GUI — необходимы для скрапинга сайтов с интенсивным JavaScript. Однако запуск множества сессий безголового браузера с одного IP — очевидный сигнал автоматизации. Сочетание безголовых браузеров с ротацией прокси решает эту проблему, распределяя запросы по тысячам резидентных IP.
Это руководство охватывает настройку прокси в Puppeteer и Playwright, стелс-плагины и стратегии ротации. Подробнее о механизмах обнаружения — в нашем руководстве по антибот-системам.
Настройка прокси в Puppeteer
Базовая конфигурация
// Puppeteer: базовая конфигурация прокси
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--proxy-server=http://gate.proxyhat.com:8080',
'--no-sandbox',
'--disable-setuid-sandbox'
]
});
const page = await browser.newPage();
// Аутентификация с прокси
await page.authenticate({
username: 'USERNAME',
password: 'PASSWORD'
});
await page.goto('https://example.com', {
waitUntil: 'networkidle2',
timeout: 30000
});
const content = await page.content();
console.log(content.substring(0, 200));
await browser.close();
SOCKS5 с Puppeteer
// Puppeteer: конфигурация SOCKS5-прокси
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--proxy-server=socks5://gate.proxyhat.com:1080'
]
});
const page = await browser.newPage();
await page.authenticate({
username: 'USERNAME',
password: 'PASSWORD'
});
Stealth-плагин Puppeteer
Стандартная конфигурация Puppeteer раскрывает десятки маркеров автоматизации. Плагин puppeteer-extra-plugin-stealth автоматически патчит эти маркеры.
// Install: npm install puppeteer-extra puppeteer-extra-plugin-stealth
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
// Применение stealth-плагина
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--proxy-server=http://gate.proxyhat.com:8080',
'--disable-blink-features=AutomationControlled',
'--window-size=1920,1080',
'--disable-dev-shm-usage'
]
});
const page = await browser.newPage();
await page.authenticate({
username: 'USERNAME',
password: 'PASSWORD'
});
// Установка реалистичного viewport
await page.setViewport({ width: 1920, height: 1080 });
// Дополнительные заголовки для согласованности
await page.setExtraHTTPHeaders({
'Accept-Language': 'en-US,en;q=0.9'
});
await page.goto('https://example.com');
Stealth-плагин патчит:
navigator.webdriver— устанавливается в undefined вместо truechrome.runtime— добавляет отсутствующие Chrome-специфичные объекты- Вендор/рендерер WebGL — реалистичные строки GPU
- Массивы плагинов и разрешений — соответствуют реальному Chrome
- Согласованность языка и платформы
Подробнее о том, что именно патчится — в нашей статье о браузерном фингерпринтинге.
Настройка прокси в Playwright
Playwright предоставляет более элегантную настройку прокси, поддерживая прокси на уровне контекста и встроенную эмуляцию устройств.
Базовая конфигурация
// Playwright: базовая настройка прокси
const { chromium } = require('playwright');
const browser = await chromium.launch({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: 'USERNAME',
password: 'PASSWORD'
}
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log(`Page title: ${title}`);
await browser.close();
Прокси на контекст (разные IP на вкладку)
// Playwright: разные прокси для каждого контекста
const { chromium } = require('playwright');
const browser = await chromium.launch();
// Контекст 1: сессия с прокси из США
const ctx1 = await browser.newContext({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: 'USERNAME-country-us-session-abc1',
password: 'PASSWORD'
},
locale: 'en-US',
timezoneId: 'America/New_York'
});
// Контекст 2: сессия с прокси из Великобритании
const ctx2 = await browser.newContext({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: 'USERNAME-country-gb-session-abc2',
password: 'PASSWORD'
},
locale: 'en-GB',
timezoneId: 'Europe/London'
});
const page1 = await ctx1.newPage();
const page2 = await ctx2.newPage();
// Каждая страница использует разный IP и локаль
await page1.goto('https://example.com');
await page2.goto('https://example.com');
Эмуляция устройства с прокси
// Playwright: реалистичная эмуляция устройства + прокси
const { chromium, devices } = require('playwright');
const browser = await chromium.launch({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: 'USERNAME',
password: 'PASSWORD'
}
});
// Эмуляция конкретного устройства с соответствующими настройками
const context = await browser.newContext({
...devices['Desktop Chrome'],
locale: 'en-US',
timezoneId: 'America/Chicago',
geolocation: { latitude: 41.8781, longitude: -87.6298 },
permissions: ['geolocation'],
colorScheme: 'light'
});
const page = await context.newPage();
await page.goto('https://example.com');
Ротация прокси в безголовых браузерах
Стратегия 1: Новый контекст на каждый запрос
Создавайте новый контекст для каждого URL — свежий IP и чистые куки.
// Playwright: ротация прокси через новые контексты
async function scrapeWithRotation(urls) {
const browser = await chromium.launch();
const results = [];
for (const url of urls) {
const sessionId = `sess-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
const context = await browser.newContext({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: `USERNAME-session-${sessionId}`,
password: 'PASSWORD'
}
});
const page = await context.newPage();
try {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
const data = await page.evaluate(() => document.title);
results.push({ url, data });
} catch (error) {
console.error(`Failed: ${url} — ${error.message}`);
} finally {
await context.close();
}
// Естественная задержка
await new Promise(r => setTimeout(r, 1000 + Math.random() * 2000));
}
await browser.close();
return results;
}
Стратегия 2: Sticky-сессии для многостраничных потоков
Используйте sticky-сессии для сохранения одного IP на нескольких страницах (пагинация, авторизация).
// Playwright: sticky-сессия для многостраничного скрапинга
async function scrapeWithStickySession(baseUrl, pageCount) {
const sessionId = `sticky-${Date.now()}`;
const browser = await chromium.launch({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: `USERNAME-session-${sessionId}`,
password: 'PASSWORD'
}
});
const context = await browser.newContext();
const page = await context.newPage();
const results = [];
for (let i = 1; i <= pageCount; i++) {
await page.goto(`${baseUrl}?page=${i}`, { waitUntil: 'networkidle' });
const items = await page.$$eval('.item', els =>
els.map(el => el.textContent.trim())
);
results.push(...items);
// Естественная задержка между страницами
await new Promise(r => setTimeout(r, 1500 + Math.random() * 1500));
}
await browser.close();
return results;
}
Стратегия 3: Параллельный скрапинг с пулом
// Playwright: параллельный скрапинг с пулом прокси
async function concurrentScrape(urls, concurrency = 5) {
const browser = await chromium.launch();
const results = [];
// Обработка URL пакетами
for (let i = 0; i < urls.length; i += concurrency) {
const batch = urls.slice(i, i + concurrency);
const promises = batch.map(async (url) => {
const sessionId = `conc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
const context = await browser.newContext({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: `USERNAME-session-${sessionId}`,
password: 'PASSWORD'
}
});
const page = await context.newPage();
try {
await page.goto(url, { timeout: 30000, waitUntil: 'domcontentloaded' });
return { url, title: await page.title(), status: 'ok' };
} catch (e) {
return { url, error: e.message, status: 'error' };
} finally {
await context.close();
}
});
const batchResults = await Promise.all(promises);
results.push(...batchResults);
// Задержка между пакетами
await new Promise(r => setTimeout(r, 2000));
}
await browser.close();
return results;
}
Playwright с Python
Для Python-разработчиков playwright предоставляет те же возможности с чистым синтаксисом.
# Python: Playwright с прокси и стелс-настройками
# pip install playwright
# playwright install chromium
from playwright.async_api import async_playwright
import asyncio
async def scrape_with_proxy():
async with async_playwright() as p:
browser = await p.chromium.launch(
proxy={
"server": "http://gate.proxyhat.com:8080",
"username": "USERNAME",
"password": "PASSWORD"
}
)
context = await browser.new_context(
viewport={"width": 1920, "height": 1080},
locale="en-US",
timezone_id="America/New_York",
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
)
page = await context.new_page()
await page.goto("https://example.com")
title = await page.title()
print(f"Title: {title}")
await browser.close()
asyncio.run(scrape_with_proxy())
Оптимизация ресурсов
Безголовые браузеры потребляют значительный объём памяти и CPU. Оптимизируйте для продакшн-нагрузок:
Блокировка ненужных ресурсов
// Playwright: блокировка изображений, шрифтов и CSS для экономии трафика
const context = await browser.newContext({
proxy: {
server: 'http://gate.proxyhat.com:8080',
username: 'USERNAME',
password: 'PASSWORD'
}
});
const page = await context.newPage();
// Блокировка несущественных ресурсов
await page.route('**/*.{png,jpg,jpeg,gif,svg,webp,woff,woff2,ttf,css}', route =>
route.abort()
);
// Блокировка трекинга и аналитики
await page.route('**/{google-analytics,gtag,facebook}**', route =>
route.abort()
);
await page.goto('https://example.com');
Управление памятью
- Закрывайте контексты после использования: Каждый открытый контекст потребляет 50-150 МБ. Всегда закрывайте по завершении.
- Ограничивайте параллельные контексты: 3-10 контекстов на экземпляр браузера в зависимости от доступной RAM.
- Перезапускайте браузер периодически: После 100-200 циклов контекстов перезапускайте для предотвращения утечек памяти.
- Используйте headless: 'new' (Puppeteer): Новый режим безголового браузера потребляет меньше памяти.
Обработка типичных проблем
Ошибки аутентификации прокси
// Обработка ошибок аутентификации прокси
try {
const response = await page.goto(url, { timeout: 30000 });
if (response.status() === 407) {
console.error('Proxy authentication failed — check credentials');
}
} catch (error) {
if (error.message.includes('net::ERR_PROXY_CONNECTION_FAILED')) {
console.error('Proxy connection failed — check proxy server availability');
}
}
Обработка таймаутов
// Повтор с экспоненциальным откатом
async function gotoWithRetry(page, url, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await page.goto(url, {
waitUntil: 'domcontentloaded',
timeout: 30000
});
} catch (error) {
if (attempt === maxRetries) throw error;
const delay = 1000 * Math.pow(2, attempt) + Math.random() * 1000;
console.log(`Retry ${attempt}/${maxRetries} after ${delay}ms`);
await new Promise(r => setTimeout(r, delay));
}
}
}
Чек-лист лучших практик
| Практика | Puppeteer | Playwright |
|---|---|---|
| Прокси на контекст | Только через аргументы запуска | Поддержка прокси на контекст |
| Стелс-патчи | puppeteer-extra-plugin-stealth | Встроенная эмуляция устройств |
| Блокировка ресурсов | page.setRequestInterception | page.route |
| Мультибраузерность | Только Chromium | Chromium, Firefox, WebKit |
| Изоляция сессий | Новый браузер на сессию | Новый контекст на сессию |
Для большинства задач скрапинга Playwright — рекомендуемый выбор благодаря превосходной поддержке прокси (на контекст), встроенной эмуляции устройств и поддержке нескольких браузеров. Сочетайте с резидентными прокси ProxyHat для лучших результатов.
Настройка прокси для конкретных языков без безголовых браузеров — в руководствах по Python, Node.js и Go. Комплексные стратегии антидетекта — в нашем руководстве по снижению обнаружения. Всегда следуйте этичным практикам скрапинга и уважайте политики доступа сайтов.






