Назад к блогу
Сеть

Per-Context Proxy: независимая сетевая идентичность для каждого контекста браузера

Настройте независимый прокси и географическую идентичность для каждого BrowserContext. Запускайте несколько регионов в одном экземпляре браузера с автоматическим выравниванием часового пояса, локали и языка.

Введение

При запуске нескольких идентичностей или региональных рабочих процессов в браузере одного прокси на всю сессию недостаточно. Если каждый контекст использует один и тот же IP-адрес, трафик от разных идентичностей может быть связан через этот общий сетевой путь. Системы отслеживания наблюдают за паттернами IP, и два аккаунта, исходящие с одного адреса в схожее время, легко коррелируются.

Per-context proxy решает эту проблему, назначая выделенный прокси каждому BrowserContext. Каждый контекст маршрутизируется через отдельный прокси-сервер, получает собственный публичный IP и географические метаданные (часовой пояс, локаль, язык), полученные из местоположения выхода прокси. В сочетании с изоляцией отпечатков по контексту каждый контекст становится полностью независимой идентичностью без общих сетевых или отпечаточных сигналов.

В этой статье рассматривается работа per-context proxy в BotBrowser, настройка в Puppeteer и Playwright, а также оптимизация производительности для многорегиональных развертываний.

Влияние на приватность

Единый прокси создает общую сетевую идентичность для всех контекстов. Даже с разными профилями отпечатков общий IP становится точкой корреляции. Рассмотрим следующие риски:

  • Корреляция по IP: два аккаунта, обращающиеся к одному сервису с одного IP, могут быть связаны, независимо от различий отпечатков
  • Географическая несогласованность: контекст, настроенный с немецким профилем отпечатка, но маршрутизируемый через американский прокси, создает очевидное несоответствие между заявленным местоположением и сетевым происхождением
  • Анализ тайминга: несколько идентичностей, использующих один прокси, могут быть коррелированы по паттернам тайминга трафика, так как все запросы исходят из одной сетевой точки

Per-context proxy устраняет эти риски. Каждый контекст имеет собственный прокси, собственный публичный IP и собственные географические метаданные. Между контекстами нет общих сетевых сигналов.

Архитектура Per-Context Proxy Единственный экземпляр BotBrowser Контекст A Профиль: Windows US TZ: America/New_York Локаль: en-US Cookies, хранилище (Изолировано) Контекст B Профиль: macOS UK TZ: Europe/London Локаль: en-GB Cookies, хранилище (Изолировано) Контекст C Профиль: Linux DE TZ: Europe/Berlin Локаль: de-DE Cookies, хранилище (Изолировано) Прокси США 203.0.113.1 Прокси UK 198.51.100.1 Прокси DE 192.0.2.1 Каждый контекст маршрутизируется через собственный прокси с соответствующими гео-данными

Техническая основа

Сетевая изоляция на уровне 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 контекстов)
Процессы браузера101
Процессы GPU101
Сетевые процессы101
Базовые затраты памяти~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.

#proxy#per-context#network#isolation#geographic-identity#multi-region