身份

时区、区域设置和语言指纹指南

时区、区域设置和语言设置如何创建地理指纹,以及如何一致地配置它们以实现完整的身份控制。

文档中心

想直接看维护中的产品文档?

这篇文章对应的主题已经有文档中心页面。需要规范流程、当前参数和长期参考时,优先看 docs。

简介

你的浏览器通过多个渠道暴露地理信息:通过 Intl API 暴露时区,通过数字和日期格式暴露区域设置,通过 navigator.languageAccept-Language 头暴露语言,以及通过 Geolocation API 暴露地理位置。这四个属性构成了浏览器身份的地理层。当它们彼此不一致或与你的 IP 地址不一致时,不一致是可见的。

BotBrowser 提供专用的 CLI 标志在引擎级别配置每个地理属性。默认情况下,BotBrowser 从代理 IP 自动派生所有地理设置,因此单个 --proxy-server 标志就能产生完全一致的地理身份。本文涵盖自动检测系统、手动覆盖标志以及多区域工作流程的配置策略。

隐私影响

地理元数据是浏览器身份中最常被检查的方面之一。追踪系统会比较:

  • IP 地理位置 vs. 时区:德国 IP 地址配 America/New_York 时区是明显的不匹配
  • 区域设置 vs. 语言de-DE 区域设置仅配 Accept-Language: en-US 是不寻常的
  • 语言 vs. IP 区域:日本 IP 仅有英语语言偏好可能表明配置错误
  • 地理位置坐标 vs. IP:如果 Geolocation API 返回东京坐标但 IP 解析到纽约,冲突很明显

这些检查简单且快速,使其成为任何追踪管线中的早期过滤器。正确获得地理一致性是任何注重隐私的浏览设置的必要基础。

BotBrowser 的自动地理检测消除了这些不匹配最常见的来源:手动配置错误。当你通过代理连接时,BotBrowser 检测代理的 IP 并自动派生时区、区域设置、语言和地理位置。

技术背景

浏览器如何暴露地理信息

时区:JavaScript 的 Intl.DateTimeFormat().resolvedOptions().timeZone 返回 IANA 时区名称(如 America/New_York)。Date 对象的 getTimezoneOffset() 方法返回以分钟为单位的 UTC 偏移。两者必须彼此一致并与声称的位置一致。

区域设置Intl.NumberFormat().resolvedOptions().localeIntl.DateTimeFormat().resolvedOptions().locale 揭示浏览器的格式区域设置。这影响数字格式(逗号 vs. 句点作为小数点)、日期格式(DD/MM vs. MM/DD)和货币格式。

语言navigator.language 返回主要语言,navigator.languages 返回完整的首选语言列表。Accept-Language HTTP 头随每个请求发送这些偏好。

地理位置navigator.geolocation.getCurrentPosition() API 返回类似 GPS 的坐标。这需要用户权限,但当授权时,坐标必须对给定的 IP 和时区来说是合理的。

一致性链

这些信号形成一个必须内部一致的链:

IP 地址 → 国家 → 时区 → 区域设置 → 语言 → 地理位置

每一步都必须从前一步逻辑推导出来。日本的代理 IP 应该产生:

  • 时区:Asia/Tokyo
  • 区域设置:ja-JP
  • 语言:ja-JP,ja,en
  • 地理位置:日本坐标(如果查询)

打断此链中的任何环节都会产生可检测的不一致。

DST 和 UTC 偏移

时区配置必须考虑夏令时(DST)。使用 UTC-5 等 UTC 偏移而不是 America/New_York 等 IANA 时区名称,在 DST 转换发生时会失败。America/New_York 在冬季是 UTC-5,夏季是 UTC-4。固定的 UTC 偏移不处理此转换,创建季节性的不匹配,揭示时区是手动配置的。

BotBrowser 内部使用 IANA 时区名称,确保全年正确的 DST 行为。

地理身份一致性链 代理 IP 203.0.113.1 时区 Asia/Tokyo 区域设置 ja-JP 语言 ja-JP, ja, en 地理位置 35.67, 139.65 BotBrowser 从代理 IP 自动派生所有设置 需要时使用 --bot-config-* 标志覆盖任何属性

常见方法及其局限性

框架级时区和区域设置

Playwright 提供每个上下文的 timezoneIdlocale 选项:

const context = await browser.newContext({
  timezoneId: 'America/New_York',
  locale: 'en-US',
});

这改变了 Intl API 行为和 navigator.language,但:

  • 地理位置坐标不受影响
  • Accept-Language 头可能不完全对齐
  • Date.getTimezoneOffset() 中的时区偏移可能不在所有上下文中一致更新

手动头设置

通过 page.setExtraHTTPHeaders() 设置 Accept-Language 改变了 HTTP 头但不改变 navigator.languagenavigator.languages。HTTP 和 JavaScript 值之间的不匹配是可检测的。

VPN 配系统时区

更改系统时区以匹配 VPN 有效但影响所有应用,不仅仅是浏览器。它还需要管理员访问权限和每次区域更改时的手动干预。

BotBrowser 的方法

自动地理检测

默认情况下,BotBrowser 从代理 IP 自动派生所有地理设置:

chrome --bot-profile="/path/to/profile.enc" \
       --proxy-server=socks5://user:pass@jp-proxy:1080

BotBrowser 检测到日本 IP 并自动配置:

  • 时区:Asia/Tokyo
  • 区域设置:ja-JP
  • 语言:ja-JP,ja,en
  • 地理位置:从 IP 近似的坐标

不需要额外标志。auto 行为是所有地理设置的默认值。

手动覆盖标志

当需要特定地理设置时,四个 CLI 标志提供完整控制:

--bot-config-timezone(ENT Tier1):设置 IANA 时区。

--bot-config-timezone=America/New_York    # 特定时区
--bot-config-timezone=auto                # 从 IP 派生(默认)
--bot-config-timezone=real                # 使用系统时区

--bot-config-locale(ENT Tier1):设置浏览器区域设置。

--bot-config-locale=en-US    # 特定区域设置
--bot-config-locale=auto     # 从 IP/语言派生(默认)

--bot-config-languages(ENT Tier1):设置语言偏好。

--bot-config-languages=en-US,en          # 特定语言
--bot-config-languages=auto              # 从 IP 派生(默认)

--bot-config-location(ENT Tier1):设置地理位置坐标。

--bot-config-location=40.7128,-74.0060   # 特定坐标
--bot-config-location=auto               # 从 IP 派生(默认)
--bot-config-location=real               # 使用系统 GPS

引擎级实现

BotBrowser 在浏览器引擎级别设置这些值,这意味着:

  • 时区Intl.DateTimeFormat().resolvedOptions().timeZoneDate.getTimezoneOffset() 都反映配置的时区,包括正确的 DST 行为
  • 区域设置:所有 Intl 格式化器(NumberFormat、DateTimeFormat、Collator)使用配置的区域设置
  • 语言navigator.languagenavigator.languagesAccept-Language HTTP 头都一致
  • 地理位置navigator.geolocation.getCurrentPosition() 返回配置的坐标

所有值在主线程、workers 和 HTTP 头中保持一致。

配置和使用

完整地理配置(CLI)

chrome --bot-profile="/path/to/profile.enc" \
       --proxy-server=socks5://user:pass@us-east.proxy:1080 \
       --bot-config-timezone=America/New_York \
       --bot-config-locale=en-US \
       --bot-config-languages=en-US,en \
       --bot-config-location=40.7128,-74.0060

常见区域配置

区域时区区域设置语言坐标
美东America/New_Yorken-USen-US,en40.7128,-74.0060
美西America/Los_Angelesen-USen-US,en34.0522,-118.2437
英国Europe/Londonen-GBen-GB,en51.5074,-0.1278
德国Europe/Berlinde-DEde-DE,de,en52.5200,13.4050
法国Europe/Parisfr-FRfr-FR,fr,en48.8566,2.3522
日本Asia/Tokyoja-JPja-JP,ja,en35.6762,139.6503
韩国Asia/Seoulko-KRko-KR,ko,en37.5665,126.9780
巴西America/Sao_Paulopt-BRpt-BR,pt,en-23.5505,-46.6333
澳大利亚Australia/Sydneyen-AUen-AU,en-33.8688,151.2093

Playwright 集成

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

(async () => {
  const browser = await chromium.launch({
    executablePath: '/path/to/botbrowser/chrome',
    args: [
      '--bot-profile=/path/to/profile.enc',
      '--proxy-server=socks5://user:pass@us-east.proxy:1080',
      '--bot-config-timezone=America/New_York',
      '--bot-config-locale=en-US',
      '--bot-config-languages=en-US,en',
      '--bot-config-location=40.7128,-74.0060',
    ],
    headless: true,
  });

  const context = await browser.newContext();
  const page = await context.newPage();

  const tz = await page.evaluate(() =>
    Intl.DateTimeFormat().resolvedOptions().timeZone
  );
  const langs = await page.evaluate(() => navigator.languages);
  const locale = await page.evaluate(() =>
    Intl.NumberFormat().resolvedOptions().locale
  );

  console.log('Timezone:', tz);     // America/New_York
  console.log('Languages:', langs); // ['en-US', 'en']
  console.log('Locale:', locale);   // en-US

  await browser.close();
})();

多区域设置

const regions = [
  {
    profile: '/profiles/us-user.enc',
    proxy: 'socks5://user:pass@us.proxy:1080',
    timezone: 'America/New_York',
    locale: 'en-US',
    languages: 'en-US,en',
    location: '40.7128,-74.0060',
  },
  {
    profile: '/profiles/de-user.enc',
    proxy: 'socks5://user:pass@de.proxy:1080',
    timezone: 'Europe/Berlin',
    locale: 'de-DE',
    languages: 'de-DE,de,en',
    location: '52.5200,13.4050',
  },
  {
    profile: '/profiles/jp-user.enc',
    proxy: 'socks5://user:pass@jp.proxy:1080',
    timezone: 'Asia/Tokyo',
    locale: 'ja-JP',
    languages: 'ja-JP,ja,en',
    location: '35.6762,139.6503',
  },
];

for (const cfg of regions) {
  const browser = await chromium.launch({
    executablePath: '/path/to/botbrowser/chrome',
    args: [
      `--bot-profile=${cfg.profile}`,
      `--proxy-server=${cfg.proxy}`,
      `--bot-config-timezone=${cfg.timezone}`,
      `--bot-config-locale=${cfg.locale}`,
      `--bot-config-languages=${cfg.languages}`,
      `--bot-config-location=${cfg.location}`,
    ],
    headless: true,
  });

  // 运行区域特定任务...
  await browser.close();
}

验证

配置地理设置后,验证所有属性:

const page = await context.newPage();

// 时区
const tz = await page.evaluate(() =>
  Intl.DateTimeFormat().resolvedOptions().timeZone
);

// 时区偏移(应对当前日期/DST 正确)
const offset = await page.evaluate(() => new Date().getTimezoneOffset());

// 从数字格式获取区域设置
const locale = await page.evaluate(() =>
  Intl.NumberFormat().resolvedOptions().locale
);

// 语言
const lang = await page.evaluate(() => navigator.language);
const langs = await page.evaluate(() => navigator.languages);

// 日期格式(区域设置特定)
const dateFormat = await page.evaluate(() =>
  new Date().toLocaleDateString()
);

// 数字格式(区域设置特定)
const numFormat = await page.evaluate(() =>
  (1234567.89).toLocaleString()
);

console.log('Timezone:', tz);
console.log('Offset:', offset);
console.log('Locale:', locale);
console.log('Language:', lang);
console.log('Languages:', langs);
console.log('Date format:', dateFormat);
console.log('Number format:', numFormat);

确认:

  1. 时区匹配预期的 IANA 名称
  2. UTC 偏移对当前日期正确(考虑 DST)
  3. 区域设置正确影响数字和日期格式
  4. 语言按预期优先顺序排列
  5. 所有值与代理 IP 地理一致

最佳实践

  1. 使用 IANA 时区名称,不要用 UTC 偏移。 America/New_York 正确处理 DST。UTC-5 不会。

  2. 按优先顺序设置语言。 德国用户通常有 de-DE,de,en。将英语作为次要语言对大多数区域来说是合理的。

  3. 将地理位置匹配到代理城市,而不是街道地址。 城市级精度足够且更现实。

  4. 保持区域设置和时区在同一区域。 ja-JP 区域设置配 Europe/London 时区是明显的不一致。

  5. 尽可能让 BotBrowser 自动检测。 auto 默认值从代理 IP 产生一致的结果,无需手动配置。

  6. 测试格式化行为,不仅仅是 API 值。 检查 toLocaleDateString()toLocaleString() 是否产生区域适当的格式。

常见问题

BotBrowser 正确处理 DST 转换吗? 是的。BotBrowser 内部使用 IANA 时区名称,其中编码了 DST 规则。Date.getTimezoneOffset() 对任何日期返回正确的偏移,包括转换。

我可以在 Playwright 中按上下文设置时区吗? Playwright 的 timezoneId 选项按上下文改变 JavaScript Intl 行为。BotBrowser 的 --bot-config-timezone 标志在引擎级别设置时区。两种方法都有效,但 BotBrowser 标志还确保 HTTP 级别的一致性。

不使用代理的自动检测会怎样? 没有代理时,BotBrowser 使用你的真实公共 IP 进行自动检测。地理设置将匹配你的实际位置。

我可以只设置时区让其余自动检测吗? 可以。你可以覆盖单个设置。例如,只设置 --bot-config-timezone 而将区域设置、语言和位置保持为 auto 是可行的。但确保时区与自动检测的值一致。

--bot-config-location 需要用户权限吗? BotBrowser 设置在页面请求地理位置权限时返回的地理位置值。用户权限提示行为由浏览器上下文设置控制。

--bot-config-languages 接受什么语言格式? 逗号分隔的 BCP 47 语言标签列表:en-US,en,fr-FR,fr。顺序决定优先级,反映在 navigator.languagesAccept-Language 头中。

不使用 --bot-profile 也能使用这些标志吗? 地理标志可以独立工作,但没有配置文件就没有指纹保护。始终使用 --bot-profile 作为基础。

设置 --bot-config-languages 时 Accept-Language 头会更新吗? 是的。每个 HTTP 请求的 Accept-Language 头反映配置的语言列表,包括用于优先排序的适当质量值(q-values)。

总结

时区、区域设置、语言和地理位置构成了浏览器身份的地理层。BotBrowser 默认从代理 IP 自动派生所有地理设置,无需手动配置即可产生一致的身份。对于特定需求,--bot-config-timezone--bot-config-locale--bot-config-languages--bot-config-location 标志在引擎级别提供完整控制。

代理设置请参阅代理配置。浏览器身份请参阅浏览器品牌切换User Agent 控制和 Client Hints。多区域工作流程请参阅多账户浏览器隔离

#Timezone#Locale#Language#Identity#Geolocation

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。