Per-Context Proxy: независимая сетевая идентичность для каждого контекста браузера
Настройте независимый прокси и географическую идентичность для каждого BrowserContext. Запускайте несколько регионов в одном экземпляре браузера с автоматическим выравниванием часового пояса, локали и языка.
Введение
При запуске нескольких идентичностей или региональных рабочих процессов в браузере одного прокси на всю сессию недостаточно. Если каждый контекст использует один и тот же IP-адрес, трафик от разных идентичностей может быть связан через этот общий сетевой путь. Системы отслеживания наблюдают за паттернами IP, и два аккаунта, исходящие с одного адреса в схожее время, легко коррелируются.
Per-context proxy решает эту проблему, назначая выделенный прокси каждому BrowserContext. Каждый контекст маршрутизируется через отдельный прокси-сервер, получает собственный публичный IP и географические метаданные (часовой пояс, локаль, язык), полученные из местоположения выхода прокси. В сочетании с изоляцией отпечатков по контексту каждый контекст становится полностью независимой идентичностью без общих сетевых или отпечаточных сигналов.
В этой статье рассматривается работа per-context proxy в BotBrowser, настройка в Puppeteer и Playwright, а также оптимизация производительности для многорегиональных развертываний.
Влияние на приватность
Единый прокси создает общую сетевую идентичность для всех контекстов. Даже с разными профилями отпечатков общий IP становится точкой корреляции. Рассмотрим следующие риски:
- Корреляция по IP: два аккаунта, обращающиеся к одному сервису с одного IP, могут быть связаны, независимо от различий отпечатков
- Географическая несогласованность: контекст, настроенный с немецким профилем отпечатка, но маршрутизируемый через американский прокси, создает очевидное несоответствие между заявленным местоположением и сетевым происхождением
- Анализ тайминга: несколько идентичностей, использующих один прокси, могут быть коррелированы по паттернам тайминга трафика, так как все запросы исходят из одной сетевой точки
Per-context proxy устраняет эти риски. Каждый контекст имеет собственный прокси, собственный публичный IP и собственные географические метаданные. Между контекстами нет общих сетевых сигналов.
Техническая основа
Сетевая изоляция на уровне BrowserContext
В Chromium BrowserContext представляет собой изолированную среду просмотра. Каждый контекст имеет собственный контейнер cookies, localStorage, sessionStorage, IndexedDB и кеш. Стандартный Chromium предоставляет эту изоляцию хранилища из коробки.
BotBrowser расширяет эту изоляцию на сетевой уровень. Когда BrowserContext получает собственный прокси, весь HTTP-, HTTPS- и WebSocket-трафик из этого контекста маршрутизируется через указанный прокси-сервер. Другие контексты в том же экземпляре браузера не затрагиваются. Это настоящая сетевая изоляция на уровне контекста, а не перехватчик на уровне страницы, который может пропустить ранние запросы или WebSocket-соединения.
Автоматическое определение географии
Когда контекст подключается через прокси, BotBrowser определяет IP выхода прокси и автоматически выводит географические настройки для этого конкретного контекста:
- Часовой пояс: определяется по геолокации IP прокси (например,
America/New_Yorkдля прокси на восточном побережье США) - Локаль: соответствует стране прокси (например,
en-US) - Языки: устанавливаются на основе региона прокси (например,
en-US,en) - Геолокация: координаты приближенно вычисляются по IP
Это происходит независимо для каждого контекста. Контекст с американским прокси получает американские географические настройки, а контекст с немецким прокси в том же браузере получает немецкие настройки. Ручная настройка часового пояса, локали или языка не требуется.
Интеграция с отпечатками по контексту
Per-context proxy работает совместно с изоляцией отпечатков по контексту BotBrowser (ENT Tier3). Каждый контекст может получить:
- Уникальный профиль отпечатка через
--bot-profile - Независимый прокси и публичный IP
- Соответствующие географические метаданные, полученные из прокси
- Изолированное хранилище (cookies, localStorage, IndexedDB)
Это означает, что каждый контекст является полностью независимой идентичностью. Между контекстами нет общих сигналов отпечатков, сетевых путей или хранилища.
Настройка
Puppeteer: многорегиональная настройка
В Puppeteer per-context proxy настраивается через CDP (Chrome DevTools Protocol). Вы создаете BrowserContext, назначаете настройки прокси и профиль отпечатка через BotBrowser.setBrowserContextFlags, затем создаете страницы в этом контексте.
const puppeteer = require('puppeteer-core');
const browser = await puppeteer.launch({
executablePath: process.env.BOTBROWSER_EXEC_PATH,
headless: true,
defaultViewport: null,
args: ['--bot-profile=/path/to/default-profile.enc'],
});
const client = await browser.target().createCDPSession();
// Контекст США с американским прокси
const usCtx = await browser.createBrowserContext({
proxyServer: 'socks5://user:pass@us-proxy.example.com:1080',
});
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: usCtx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/us-profile.enc',
'--proxy-ip=203.0.113.1',
],
});
const usPage = await usCtx.newPage();
// Контекст UK с британским прокси
const ukCtx = await browser.createBrowserContext({
proxyServer: 'socks5://user:pass@uk-proxy.example.com:1080',
});
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ukCtx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/uk-profile.enc',
'--proxy-ip=198.51.100.1',
],
});
const ukPage = await ukCtx.newPage();
// Контекст DE с немецким прокси
const deCtx = await browser.createBrowserContext({
proxyServer: 'socks5://user:pass@de-proxy.example.com:1080',
});
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: deCtx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/de-profile.enc',
'--proxy-ip=192.0.2.1',
],
});
const dePage = await deCtx.newPage();
// Каждый контекст навигирует со своим прокси и географической идентичностью
await Promise.all([
usPage.goto('https://example.com'),
ukPage.goto('https://example.com'),
dePage.goto('https://example.com'),
]);
await browser.close();
Важно: BotBrowser.setBrowserContextFlags должен быть вызван до создания любой страницы в этом контексте. Процесс рендерера читает свои флаги при запуске. Если страница уже существует, новые флаги не применятся.
Puppeteer: прокси только через botbrowserFlags
Вы также можете настроить прокси полностью через botbrowserFlags, без передачи proxyServer в createBrowserContext:
const ctx = await browser.createBrowserContext();
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ctx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/profile.enc',
'--proxy-server=socks5://user:pass@proxy.example.com:1080',
'--proxy-ip=203.0.113.1',
'--proxy-bypass-list=localhost;127.0.0.1',
],
});
const page = await ctx.newPage();
Этот подход настраивает все параметры прокси (сервер, IP, правила обхода) в одном месте.
Playwright: прокси по контексту
Playwright предоставляет нативную поддержку прокси по контексту через browser.newContext():
const { chromium } = require('playwright-core');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: ['--bot-profile=/path/to/profile.enc'],
headless: true,
});
// Контекст США
const usContext = await browser.newContext({
proxy: { server: 'socks5://us-proxy:1080', username: 'user', password: 'pass' },
});
// Контекст Германии
const deContext = await browser.newContext({
proxy: { server: 'socks5://de-proxy:1080', username: 'user', password: 'pass' },
});
// Каждый контекст автоматически получает географические настройки своего прокси
const usPage = await usContext.newPage();
const dePage = await deContext.newPage();
await usPage.goto('https://example.com');
await dePage.goto('https://example.com');
BotBrowser автоматически определяет часовой пояс, локаль и язык для каждого контекста на основе IP выхода его прокси.
Пропуск определения IP с --proxy-ip
Прокси каждого контекста вызывает запрос определения IP для вычисления географических настроек. Если вы уже знаете IP выхода прокси, этот шаг можно пропустить с помощью --proxy-ip:
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ctx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/profile.enc',
'--proxy-server=socks5://user:pass@proxy.example.com:1080',
'--proxy-ip=203.0.113.1', // Пропустить запрос IP, использовать этот IP для гео-определения
],
});
Это устраняет задержку запроса IP для каждого контекста, что особенно полезно при последовательном создании множества контекстов.
Селективная маршрутизация с proxy-bypass-rgx
Используйте --proxy-bypass-rgx для прямой маршрутизации определенных URL вместо прохождения через прокси. Это снижает потребление полосы пропускания прокси на статических ресурсах или внутренних сервисах:
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ctx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/profile.enc',
'--proxy-server=socks5://user:pass@proxy.example.com:1080',
'--proxy-bypass-list=localhost;127.0.0.1',
'--proxy-bypass-rgx=\\.(js|css|png|jpg|svg)(\\?|$)',
],
});
--proxy-bypass-list использует стандартный список хостов Chromium, разделенный точками с запятой. --proxy-bypass-rgx использует синтаксис регулярных выражений RE2 и сопоставляется с именем хоста и путем URL.
Типичные сценарии
Многорегиональное тестирование в одном браузере
Запускайте контексты США, UK и Германии одновременно в одном экземпляре браузера. Каждый контекст получает разный прокси, профиль отпечатка и географическую идентичность:
const regions = [
{
name: 'US',
proxy: 'socks5://user:pass@us.proxy.example.com:1080',
ip: '203.0.113.1',
profile: '/path/to/us-profile.enc',
},
{
name: 'UK',
proxy: 'socks5://user:pass@uk.proxy.example.com:1080',
ip: '198.51.100.1',
profile: '/path/to/uk-profile.enc',
},
{
name: 'DE',
proxy: 'socks5://user:pass@de.proxy.example.com:1080',
ip: '192.0.2.1',
profile: '/path/to/de-profile.enc',
},
];
const client = await browser.target().createCDPSession();
for (const region of regions) {
const ctx = await browser.createBrowserContext({
proxyServer: region.proxy,
});
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ctx._contextId,
botbrowserFlags: [
`--bot-profile=${region.profile}`,
`--proxy-ip=${region.ip}`,
],
});
const page = await ctx.newPage();
await page.goto('https://example.com');
// Проверить географическую идентичность
const tz = await page.evaluate(() =>
Intl.DateTimeFormat().resolvedOptions().timeZone
);
const lang = await page.evaluate(() => navigator.language);
console.log(`${region.name}: timezone=${tz}, language=${lang}`);
}
Per-Context: разный профиль + разный прокси
Каждый контекст может использовать совершенно разный профиль отпечатка. Профиль Windows с американским прокси и профиль macOS с британским прокси, все в одном браузере:
// Идентичность Windows + прокси США
const winCtx = await browser.createBrowserContext({
proxyServer: 'socks5://user:pass@us-proxy.example.com:1080',
});
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: winCtx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/windows-profile.enc',
'--proxy-ip=203.0.113.1',
],
});
// Идентичность macOS + прокси UK
const macCtx = await browser.createBrowserContext({
proxyServer: 'socks5://user:pass@uk-proxy.example.com:1080',
});
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: macCtx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/macos-profile.enc',
'--proxy-ip=198.51.100.1',
],
});
Переключение прокси в реальном времени
Для сценариев, требующих смены прокси контекста после создания (например, географическая ротация внутри сессии), используйте BotBrowser.setBrowserContextProxy (ENT Tier3):
const ctx = await browser.createBrowserContext();
const page = await ctx.newPage();
const client = await page.createCDPSession();
// Начать с прокси США
await client.send('BotBrowser.setBrowserContextProxy', {
browserContextId: ctx._contextId,
proxyServer: 'socks5://user:pass@us-proxy.example.com:1080',
proxyIp: '203.0.113.1',
});
await page.goto('https://example.com');
// Переключиться на прокси UK в реальном времени
await client.send('BotBrowser.setBrowserContextProxy', {
browserContextId: ctx._contextId,
proxyServer: 'socks5h://user:pass@uk-proxy.example.com:1080',
proxyIp: '198.51.100.1',
proxyBypassList: 'localhost;127.0.0.1',
proxyBypassRgx: 'cdn\\.example\\.com|/static/',
});
await page.goto('https://example.co.uk');
// Переключиться на прокси Японии
await client.send('BotBrowser.setBrowserContextProxy', {
browserContextId: ctx._contextId,
proxyServer: 'socks5://user:pass@jp-proxy.example.com:1080',
proxyIp: '192.0.2.1',
});
await page.goto('https://example.jp');
После каждого переключения BotBrowser заново определяет географические настройки и применяет их к контексту. Обновление географии вступает в силу при следующей навигации основного фрейма.
Оптимизация производительности
Используйте --proxy-ip для снижения нагрузки запросов
Когда вы знаете IP выхода каждого прокси, всегда передавайте --proxy-ip. Без него BotBrowser выполняет запрос определения IP для каждого контекста при первой навигации. При более чем 10 контекстах эти запросы накапливаются:
// Без --proxy-ip: каждый контекст делает запрос определения IP
// С --proxy-ip: гео-определение мгновенное, без сетевого запроса
const contexts = proxies.map(async (proxy) => {
const ctx = await browser.createBrowserContext({ proxyServer: proxy.server });
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ctx._contextId,
botbrowserFlags: [
'--bot-profile=/path/to/profile.enc',
`--proxy-ip=${proxy.knownIp}`,
],
});
return ctx;
});
Общие процессы экономят ресурсы
Per-context proxy в одном экземпляре браузера разделяет GPU-процесс, процесс браузера и вспомогательные процессы. По сравнению с запуском отдельных экземпляров браузера для каждого прокси этот подход экономит:
| Ресурс | Отдельные экземпляры (10 прокси) | Per-Context (10 контекстов) |
|---|---|---|
| Процессы браузера | 10 | 1 |
| Процессы GPU | 10 | 1 |
| Сетевые процессы | 10 | 1 |
| Базовые затраты памяти | ~500 МБ | ~50 МБ |
| Время создания контекста | 1-3 секунды каждый | Миллисекунды каждый |
Комбинация с отпечатками по контексту
Когда вы назначаете и прокси, и профиль отпечатка для каждого контекста, каждый контекст становится полностью независимой идентичностью без накладных расходов отдельных экземпляров браузера:
// Один экземпляр браузера, 3 полные идентичности
const identities = [
{ profile: '/profiles/win-us.enc', proxy: 'socks5://us:1080', ip: '203.0.113.1' },
{ profile: '/profiles/mac-uk.enc', proxy: 'socks5://uk:1080', ip: '198.51.100.1' },
{ profile: '/profiles/linux-de.enc', proxy: 'socks5://de:1080', ip: '192.0.2.1' },
];
for (const id of identities) {
const ctx = await browser.createBrowserContext({ proxyServer: id.proxy });
await client.send('BotBrowser.setBrowserContextFlags', {
browserContextId: ctx._contextId,
botbrowserFlags: [
`--bot-profile=${id.profile}`,
`--proxy-ip=${id.ip}`,
],
});
// Каждый контекст: уникальный отпечаток + уникальный прокси + уникальная гео = полная независимость
}
Проверка
После настройки per-context proxy проверьте каждый контекст независимо:
async function verifyContext(context, label) {
const page = await context.newPage();
// Проверить публичный IP
await page.goto('https://httpbin.org/ip');
const ipData = await page.evaluate(() => document.body.textContent);
console.log(`[${label}] IP: ${ipData.trim()}`);
// Проверить часовой пояс
const tz = await page.evaluate(() =>
Intl.DateTimeFormat().resolvedOptions().timeZone
);
console.log(`[${label}] Часовой пояс: ${tz}`);
// Проверить язык
const lang = await page.evaluate(() => navigator.language);
console.log(`[${label}] Язык: ${lang}`);
// Проверить локаль
const locale = await page.evaluate(() =>
Intl.NumberFormat().resolvedOptions().locale
);
console.log(`[${label}] Локаль: ${locale}`);
await page.close();
}
await verifyContext(usCtx, 'US');
await verifyContext(ukCtx, 'UK');
await verifyContext(deCtx, 'DE');
Убедитесь, что каждый контекст показывает разный IP, часовой пояс и локаль, соответствующие географическому расположению прокси.
Часто задаваемые вопросы
Какой уровень лицензии требуется для per-context proxy?
Per-context proxy с изоляцией отпечатков требует ENT Tier3. Переключение прокси в реальном времени через BotBrowser.setBrowserContextProxy также требует ENT Tier3.
Можно ли использовать Playwright для per-context proxy?
Да. Playwright нативно поддерживает прокси по контексту через browser.newContext({ proxy: ... }). BotBrowser автоматически определяет географические настройки для каждого контекста Playwright.
Нужно ли вызывать setBrowserContextFlags до создания страницы?
Да. Процесс рендерера читает свои флаги при запуске. Если страница уже существует в контексте, новые флаги не применятся. Правильный порядок: createBrowserContext -> setBrowserContextFlags -> newPage.
Можно ли изменить прокси контекста после создания?
Да, через BotBrowser.setBrowserContextProxy (ENT Tier3). Это позволяет переключать прокси в реальном времени без пересоздания контекста. Географические настройки перевычисляются при следующей навигации основного фрейма.
Какие протоколы прокси поддерживаются?
Все протоколы, поддерживаемые --proxy-server, работают по контексту: socks5://, socks5h://, http://, https://. Все поддерживают встроенную аутентификацию (user:pass@host:port).
Сколько контекстов может работать одновременно? Жесткого ограничения нет. Каждый контекст потребляет память пропорционально количеству открытых страниц и кешированных ресурсов. На практике десятки или сотни контекстов могут работать в одном экземпляре браузера при достаточном объеме RAM.
BotBrowser автоматически определяет географию для каждого контекста? Да. Каждый контекст с отдельным прокси получает независимое гео-определение. BotBrowser определяет IP выхода и настраивает часовой пояс, локаль и язык для этого конкретного контекста.
Что произойдет, если не задать --proxy-ip?
BotBrowser выполнит автоматический запрос определения IP при первой навигации каждого контекста. Это работает корректно, но добавляет небольшую задержку. Установка --proxy-ip устраняет этот запрос.
Можно ли использовать разные правила обхода для каждого контекста?
Да. --proxy-bypass-list и --proxy-bypass-rgx могут быть настроены для каждого контекста через botbrowserFlags.
Итоги
Per-context proxy обеспечивает полную сетевую изоляцию для каждого BrowserContext в рамках одного экземпляра браузера. Каждый контекст маршрутизируется через собственный прокси, получает независимый публичный IP и географические метаданные (часовой пояс, локаль, язык), автоматически полученные из местоположения выхода прокси. В сочетании с профилями отпечатков по контексту каждый контекст работает как полностью независимая идентичность.
Для основ работы с прокси и деталей протоколов смотрите Настройка прокси. Для переключения прокси в реальном времени в существующих контекстах смотрите Динамическое переключение прокси. Для полной изоляции нескольких идентичностей смотрите Изоляция многоаккаунтного браузера. Для защиты от утечек DNS и WebRTC во всех контекстах комбинируйте с Предотвращение утечек DNS и Предотвращение утечек WebRTC.