时区、区域设置和语言指纹指南
时区、区域设置和语言设置如何创建地理指纹,以及如何一致地配置它们以实现完整的身份控制。
简介
你的浏览器通过多个渠道暴露地理信息:通过 Intl API 暴露时区,通过数字和日期格式暴露区域设置,通过 navigator.language 和 Accept-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().locale 和 Intl.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 行为。
常见方法及其局限性
框架级时区和区域设置
Playwright 提供每个上下文的 timezoneId 和 locale 选项:
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.language 或 navigator.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().timeZone和Date.getTimezoneOffset()都反映配置的时区,包括正确的 DST 行为 - 区域设置:所有
Intl格式化器(NumberFormat、DateTimeFormat、Collator)使用配置的区域设置 - 语言:
navigator.language、navigator.languages和Accept-LanguageHTTP 头都一致 - 地理位置:
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_York | en-US | en-US,en | 40.7128,-74.0060 |
| 美西 | America/Los_Angeles | en-US | en-US,en | 34.0522,-118.2437 |
| 英国 | Europe/London | en-GB | en-GB,en | 51.5074,-0.1278 |
| 德国 | Europe/Berlin | de-DE | de-DE,de,en | 52.5200,13.4050 |
| 法国 | Europe/Paris | fr-FR | fr-FR,fr,en | 48.8566,2.3522 |
| 日本 | Asia/Tokyo | ja-JP | ja-JP,ja,en | 35.6762,139.6503 |
| 韩国 | Asia/Seoul | ko-KR | ko-KR,ko,en | 37.5665,126.9780 |
| 巴西 | America/Sao_Paulo | pt-BR | pt-BR,pt,en | -23.5505,-46.6333 |
| 澳大利亚 | Australia/Sydney | en-AU | en-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);
确认:
- 时区匹配预期的 IANA 名称
- UTC 偏移对当前日期正确(考虑 DST)
- 区域设置正确影响数字和日期格式
- 语言按预期优先顺序排列
- 所有值与代理 IP 地理一致
最佳实践
-
使用 IANA 时区名称,不要用 UTC 偏移。
America/New_York正确处理 DST。UTC-5不会。 -
按优先顺序设置语言。 德国用户通常有
de-DE,de,en。将英语作为次要语言对大多数区域来说是合理的。 -
将地理位置匹配到代理城市,而不是街道地址。 城市级精度足够且更现实。
-
保持区域设置和时区在同一区域。
ja-JP区域设置配Europe/London时区是明显的不一致。 -
尽可能让 BotBrowser 自动检测。
auto默认值从代理 IP 产生一致的结果,无需手动配置。 -
测试格式化行为,不仅仅是 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.languages 和 Accept-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。多区域工作流程请参阅多账户浏览器隔离。