返回博客
网络

动态代理切换与每上下文代理配置

在 BotBrowser 中配置运行时代理切换与每个浏览上下文的代理设置,以便同时管理多个网络身份。

介绍

许多隐私工作流需要在同一浏览器会话中使用多个代理:针对不同账户、地域或目标域名使用不同代理。静态代理(浏览器生命周期内唯一代理)在这些场景下受限。

BotBrowser 通过 Playwright 与 Puppeteer 的上下文 API 支持动态代理切换。每个浏览上下文都能通过不同代理路由流量并拥有独立地域身份,可以在运行时创建与关闭上下文而无需重启浏览器。本篇介绍每上下文代理配置、代理轮换策略与复杂工作流的多代理部署方案。

隐私影响

若多个账户共享同一代理,其流量会被 IP 地址关联,可能被追踪系统根据相似访问时段关联账户。即使指纹配置不同,共享的网络身份也会造成关联。

每上下文代理分配可以解决此问题:每个上下文使用独立代理,流量不会共享 IP。配合 BotBrowser 的上下文级指纹隔离,每个上下文呈现完全独立的身份:不同指纹、不同 IP、不同地理元数据。

动态代理切换对跨区域工作流也很重要:需要在美国与德国之间切换身份的任务,可通过更换代理并由 BotBrowser 自动调整时区、区域设置与语言来实现。

技术背景

浏览上下文与网络隔离

在 Playwright 或 Puppeteer 中,浏览上下文是单一浏览器实例内的隔离会话,拥有独立的 cookie、localStorage、sessionStorage 与缓存。Playwright 允许为每个上下文配置独立的代理,从而实现网络层面的隔离。

当使用 browser.newContext({ proxy: ... }) 创建上下文时,该上下文的所有流量都会通过指定代理,其它上下文不受影响。

静态代理 vs 每上下文代理

静态配置会在浏览器启动时通过 --proxy-server 指定,作用于整个实例;而每上下文配置在创建上下文时单独指定:

chrome --bot-profile="/path/to/profile.enc" \
       --proxy-server=socks5://user:pass@proxy:1080
const context = await browser.newContext({
  proxy: { server: 'socks5://proxy:1080', username: 'user', password: 'pass' },
});

若上下文未指定代理,则继承浏览器级默认代理。

BotBrowser 对上下文代理的扩展

标准 Chromium 与 Playwright 支持上下文代理,但不会为每个上下文自动派生地域设置。BotBrowser 扩展了该行为:当为上下文配置代理时,会自动从代理 IP 派生时区、区域和语言,从而为该上下文提供完整的地域身份。

常见方案与局限

启动独立浏览器实例

为每个代理启动一个浏览器实例可行,但资源开销大:每个实例包含独立的渲染进程与辅助进程,内存与 CPU 使用明显增加。

框架级代理轮换

通过 page.route() 或拦截器实现的代理轮换在 JavaScript/CDP 层工作,存在启动时使用错误代理、WebSocket 未覆盖以及 DNS 预取泄漏等问题。

代理中间件

本地代理中间件负责上游代理的轮换,增加了基础设施复杂度与单点故障,同时会引入延迟。

BotBrowser 的方法

每上下文代理与自动派生

BotBrowser 的每上下文代理支持(ENT Tier1)确保每个上下文都具有完整地域身份:

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' },
});

每个上下文将自动获得与代理地理位置匹配的时区、区域与语言设置。

为上下文手动覆盖地域设置

若需精确控制,可在创建上下文时同时指定 localetimezone

return browser.newContext({
  proxy: { server: config.proxyUrl, username: config.user, password: config.pass },
  locale: config.locale,
  timezoneId: config.timezone,
});

请求间的代理轮换

若需在导航间使用不同 IP,建议为每次轮换创建新上下文并在使用后关闭,确保状态干净(无 cookie、缓存等)。

会话粘性代理分配

对于需要持续代理的账户,保持上下文打开并在多次加载中复用该上下文:

contexts[account.name] = await browser.newContext({
  proxy: { server: account.proxy, username: 'user', password: 'pass' },
});

配置与使用

CLI 默认 + 每上下文覆盖

可以在 CLI 层设置默认代理,再在创建上下文时覆盖:

// 浏览器使用默认代理
const defaultCtx = await browser.newContext();

// 特殊上下文覆盖代理
const specialCtx = await browser.newContext({ proxy: { server: 'socks5://special-proxy:1080', username: 'u', password: 'p' } });

与 BotBrowser CLI 标志结合

结合 --bot-local-dns--bot-webrtc-ice 等全局标志,可防止 DNS 与 WebRTC 泄漏,保护所有上下文。

Puppeteer 的多实例方法

Puppeteer 对每上下文代理的支持有限,通常需要为不同代理启动独立浏览器实例。

验证

通过访问 https://httpbin.org/ip、检查 Intl.DateTimeFormat().resolvedOptions().timeZone 与 locale,分别验证每个上下文的 IP、时区与语言。

最佳实践

  1. 使用完成后关闭上下文以释放资源。
  2. 优先使用 Playwright 实现每上下文代理。
  3. 保持代理地理与 locale/时区一致。
  4. 全局设置 --bot-local-dns--bot-webrtc-ice 防止泄漏。
  5. 为不同账户使用不同指纹配置以实现完整隔离。
  6. 避免使用 page.authenticate(),请在代理 URL 中内嵌凭据。

常见问题

代理创建后无法更改;切换代理需关闭并重建上下文。上下文数量没有硬限制,但受主机内存影响。Per-context 支持 SOCKS5H,BotBrowser 会自动派生地域信息。

总结

动态代理切换结合 BotBrowser 的自动地理派生,能在单一浏览器实例内为每个上下文提供完整的网络身份:独立 IP、匹配时区与 locale,以及一致的语言设置。

title: "动态代理切换与按上下文代理配置" description: "了解如何在 BotBrowser 中配置运行时代理切换和按上下文代理设置,同时管理多个网络身份。" date: "2025-09-16" locale: zh category: network tags: ["proxy", "dynamic", "switching", "per-context", "network"] published: true

为什么需要动态代理切换

许多工作流需要在整个浏览器会话中使用多个代理。您可能需要在页面加载之间轮换代理、为不同的浏览器上下文分配不同的代理,或根据目标域名切换代理服务器。BotBrowser 通过 Playwright 的上下文 API 支持运行时代理切换和按上下文代理分配。

静态与动态配置

最简单的方法是在启动时使用 --proxy-server 设置代理:

chrome --bot-profile="/profiles/windows-chrome-122.enc" \
       --proxy-server=socks5://user:pass@proxy-host:1080 \
       --user-data-dir="$(mktemp -d)"

对于多身份工作流,按上下文代理更灵活:

const { chromium } = require('playwright-core');

const browser = await chromium.launch({
  executablePath: '/path/to/botbrowser/chrome',
  args: ['--bot-profile=/profiles/windows-chrome-122.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' },
});

每个上下文通过自己的代理独立路由流量。

按上下文地理身份

将代理切换与每个上下文的区域设置结合:

async function createGeoContext(browser, config) {
  return browser.newContext({
    proxy: { server: config.proxyUrl, username: config.user, password: config.pass },
    locale: config.locale,
    timezoneId: config.timezone,
  });
}

const usCtx = await createGeoContext(browser, {
  proxyUrl: 'socks5://us-east:1080', user: 'u', pass: 'p',
  locale: 'en-US', timezone: 'America/New_York',
});

const jpCtx = await createGeoContext(browser, {
  proxyUrl: 'socks5://jp-tokyo:1080', user: 'u', pass: 'p',
  locale: 'ja-JP', timezone: 'Asia/Tokyo',
});

每个上下文都有匹配的 IP 地址、区域设置和时区,形成完整的地理身份。

请求间代理轮换

对于跨导航的 IP 多样性,每次轮换创建新的上下文:

const proxyPool = [
  'socks5://user:pass@proxy-1:1080',
  'socks5://user:pass@proxy-2:1080',
  'socks5://user:pass@proxy-3:1080',
];

async function navigateWithRotation(browser, url, index) {
  const context = await browser.newContext({
    proxy: { server: proxyPool[index % proxyPool.length] },
  });
  const page = await context.newPage();
  await page.goto(url);
  const content = await page.content();
  await context.close();
  return content;
}

结合 BotBrowser CLI 标志

为获得最高地理一致性,将按上下文代理与 BotBrowser 的 CLI 级区域标志结合:

const browser = await chromium.launch({
  executablePath: '/path/to/botbrowser/chrome',
  args: [
    '--bot-profile=/profiles/windows-chrome-122.enc',
    '--bot-config-timezone=America/New_York',
    '--bot-config-locale=en-US',
    '--bot-config-languages=en-US,en',
  ],
  headless: true,
});

要点

  • 静态代理配置在启动时应用于所有流量
  • 按上下文代理允许在单个浏览器实例中使用不同的网络身份
  • 将代理设置与区域和时区结合以获得完整的地理身份
  • BotBrowser 支持带嵌入凭据的 SOCKS5、HTTP 和 HTTPS 协议

开始使用

  1. GitHub 下载 BotBrowser
  2. 设置代理提供商或您自己的代理基础设施
  3. 使用 Playwright 的 browser.newContext({ proxy: ... }) 进行按上下文路由
  4. 结合 --bot-config-timezone--bot-config-locale 实现地理一致性
#proxy#dynamic#switching#per-context#network