要让 Camoufox 搭配住宅代理运行,只需向 Camoufox() 或 AsyncCamoufox() 传入 Playwright 风格的 proxy 字典,设置 geoip=True,让它根据出口 IP 读取时区、语言区域和地理位置,再使用粘性会话,确保 Camoufox 启动时查询到的 IP 就是你实际浏览所用的 IP。Camoufox 是一个在 C++ 层打指纹补丁的 Firefox 构建,而不是一组 JavaScript 覆盖脚本,所以留给你的工作,是让网络身份和浏览器身份保持一致。本文其余部分是代码、背后的检查逻辑,以及 Camoufox 不适用的场景。
Camoufox 是什么,为什么要配住宅代理
Camoufox 是一个面向数据采集和 AI 智能体的开源 Firefox 分支。你可以在 Python 中用常规的 Playwright API 驱动它(PyPI 上的 camoufox 包),2026 年 9 月起也可以用官方的 npm 启动器。它的 README 写道,数据是“在 C++ 实现层被拦截的”,因此页面检查 navigator、屏幕、WebGL 或字体时,看到的是原生 getter,而不是被改写过的 JavaScript 函数。
这与 Chromium 一侧的工具思路不同。Patchright 是打过补丁的 Playwright 驱动,它不改 Chrome 本身,而是阻止驱动通过 Chrome DevTools Protocol(CDP)做出可被检测的操作,例如调用 Runtime.enable。nodriver 则完全抛开 WebDriver,直接用 CDP 与原版 Chrome 通信。这两者都是让自动化的 Chrome 看起来像普通 Chrome。Camoufox 则让自动化的 Firefox 看起来像各式各样的真实 Firefox 安装,Playwright 通过 Firefox 自己的自动化协议 Juggler 来控制它,而不是 CDP。Camoufox 的补丁为 Juggler 提供页面的隔离副本,因此 Playwright 的辅助对象(例如 window.__playwright__binding__)对页面脚本始终不可见。
之所以需要住宅代理,是因为 Camoufox 藏不住 IP。每次启动都会生成一个新的设备身份:操作系统、屏幕、GPU、字体、语音、语言。如果这个身份声称“德国的家用台式机”,连接却来自弗吉尼亚的数据中心网段,指纹上的功夫就全白费了。README 明确写道,Camoufox“旨在配合轮换代理使用(最好是住宅 IP)”。
安装 Camoufox 并下载浏览器
安装分两步:先装 Python 包,再单独下载打过补丁的 Firefox 二进制文件。
pip install -U "camoufox[geoip]"
python -m camoufox fetch
[geoip] 这个 extra 会加装 geoip2 读取器,Camoufox 会随之下载一份地理位置数据集。安装文档称它是可选项,但“如果你在使用代理,强烈推荐安装”,而且没有它 geoip=True 无法运行。锁定依赖版本时,有两点需要注意:
- 截至 2026 年 10 月初,PyPI 上的当前稳定版是
camoufox 0.5.6(2026 年 9 月 6 日发布),基于 Firefox 152 构建。9 月底,基于 Firefox 156 的构建正以 GitHub 预发布版和0.5.7b*测试版的形式发布。除非你需要某个特定修复,否则请使用稳定版。 - 该包要求 Python 3.10 或更高版本,其
pyproject.toml锁定了playwright<1.63,因为服务器模式导入了 Playwright 的一个私有模块。如果项目里其他依赖需要最新版 Playwright,就会出现冲突。
Python API:同步、异步与关键参数
Camoufox 封装了 Playwright 的 Firefox 启动器,所以拿到浏览器对象之后,所有 Playwright 调用都照常可用。同步和异步入口都是上下文管理器:
from camoufox.sync_api import Camoufox
with Camoufox(headless=True) as browser:
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
import asyncio
from camoufox.async_api import AsyncCamoufox
async def main():
async with AsyncCamoufox(headless=True) as browser:
page = await browser.new_page()
await page.goto("https://example.com")
print(await page.title())
asyncio.run(main())
对走代理的任务来说,下面这些关键字参数最重要。说明来自使用文档以及 launch_options() 在 pythonlib 源码中的 docstring:
proxy:Playwright 代理字典(server、username、password)。如果设置了geoip=True,Camoufox 还会在启动时通过该代理发出一次请求,以获取出口 IP。geoip:设为True时自动查询出口 IP,也可以直接传入一个 IP 字符串。Camoufox 会根据该 IP 设置经纬度、时区、国家、语言区域和 WebRTC IP。geoip_db用于选择数据库。2026 年 9 月 30 日,main 分支把“GeoIP AIO”设为默认并弃用了 GeoLite2,请确认你安装的版本用的是哪一个。locale:可以是明确的语言区域如"en-US",也可以是国家代码如"US"(Camoufox 会按该国使用者的语言分布挑选一种语言),或者一个列表。第一项决定IntlAPI 的结果。humanize:设为True,或者用浮点数指定光标移动的最长时间(秒)。稳定版 0.5.6 仍使用贝塞尔曲线。main 分支在 2026 年 9 月 24 日改为回放 Cursory 数据集中录制的真人鼠标轨迹,因此只有 Firefox 156 预发布版或更新的构建才有这一功能。headless:默认为False。True使用 Firefox 无头模式,Camoufox 对其打了补丁,使之看起来像普通窗口。"virtual"则在 Xvfb 虚拟显示器中以有头模式运行浏览器,该选项仅限 Linux,并需要安装xvfb包。os:把生成的身份限定为"windows"、"macos"、"linux"或它们的列表。block_webrtc、block_images、block_webgl:开关项。项目自己的警告提到,有报告称屏蔽 WebGL 或图片会在主流 WAF 上引发检测。
虚拟显示器文档解释了为什么要用 "virtual":Camoufox 虽然修补了无头模式,但“以无头模式运行将来仍可能被检测到”。在 Linux 服务器上,Xvfb 只多占一点内存,却能消除一整类无头特征,通常很值得。
完整示例:按国家定位、粘性会话、身份一致
下面的示例通过 ProxyHat 网关开启一个使用德国出口的多步会话,让 Camoufox 根据出口 IP 推导时区和语言区域,并在开始正式工作前检查身份是否自洽。国家和会话都写在代理用户名里。
import asyncio
import secrets
from camoufox.async_api import AsyncCamoufox
PROXY_USER = "USERNAME"
PROXY_PASS = "PASSWORD"
def proxy_for(country: str, session_id: str) -> dict:
# Sticky session + country target, both encoded in the username
return {
"server": "http://gate.proxyhat.com:8080",
"username": f"{PROXY_USER}-country-{country}-sid-{session_id}-ttl-10m",
"password": PROXY_PASS,
}
COHERENCE_JS = """() => ({
tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
offsetMin: new Date().getTimezoneOffset(),
lang: navigator.language,
langs: navigator.languages,
platform: navigator.platform,
})"""
async def run(country: str = "DE") -> None:
session_id = secrets.token_hex(4) # one IP for the whole flow
async with AsyncCamoufox(
proxy=proxy_for(country, session_id),
geoip=True, # timezone/locale/geo/WebRTC from exit IP
humanize=True, # humanized cursor movement
headless="virtual", # Linux + Xvfb; use headless=True elsewhere
os=["windows", "macos"],
) as browser:
page = await browser.new_page()
# 1. What does the outside world see?
await page.goto("https://ipinfo.io/json")
exit_info = await page.evaluate("() => JSON.parse(document.body.innerText)")
# 2. What does the browser claim?
claimed = await page.evaluate(COHERENCE_JS)
print("exit:", exit_info.get("ip"), exit_info.get("country"), exit_info.get("timezone"))
print("browser:", claimed)
if exit_info.get("timezone") != claimed["tz"]:
raise RuntimeError("timezone does not match exit IP; abort before real traffic")
# 3. Real multi-step work on the same IP
await page.goto("https://example.com/", wait_until="domcontentloaded")
# ... log in, paginate, submit, all on the same session_id
asyncio.run(run("DE"))
为什么这样写:
- 使用
geoip=True时,粘性会话必不可少。查询只在浏览器启动时进行一次:Camoufox 的public_ip()通过你的代理向一个公共 IP 回显服务发请求,再根据返回结果构建身份。如果用户名里没有会话参数,轮换网关可能给下一个连接分配另一个住宅 IP。在只有一个时区的国家,这很少暴露问题;但在美国、俄罗斯、巴西或澳大利亚,第二个 IP 可能与浏览器报告的时区相差好几个时区。粘性会话能保证查询所用 IP 与浏览所用 IP 是同一个(详见我们的粘性会话与轮换会话指南)。 - 每个浏览器一个会话 ID,而不是每个页面一个。轮换的方式是关闭浏览器,再用新的
session_id启动一个新的。这样 IP 和指纹会同时更换,这才像一位不同的访客。 - ipinfo 检查是一道低成本的绊线。任何 IP 地理定位接口都可以。关键是在向目标站点发请求之前,比较网络层给出的信息和浏览器给出的信息。各家地理定位数据库在边界情况下本就有分歧,所以出现不一致时应当重启,而不是认定哪里坏了。
- 优先使用 HTTP 端点。Playwright 的网络文档只为 HTTP(S) 代理说明了用户名/密码认证。SOCKS5(
gate.proxyhat.com:1080)作为代理类型是支持的,但浏览器里使用带认证的 SOCKS 恰恰是最容易出问题的地方。更全面的取舍见 HTTP 与 SOCKS5 对比。
指纹一致性检查清单
一致性指的是:出口 IP 所在国家、时区、语言、WebRTC 地址、操作系统、字体和 GPU 共同描述的是同一个地点的一台合理的机器。Camoufox 负责浏览器这一侧,多数失败都源于你自己覆盖的设置。扩大规模之前请逐项检查:
- 出口 IP 国家 ↔ 时区。同时检查
Intl.DateTimeFormat().resolvedOptions().timeZone和Date.getTimezoneOffset()。检测脚本会把 IP 地理定位得出的时区与浏览器时区对比,两者不一致是最古老的代理特征之一。在粘性会话上使用geoip=True,两者天然一致。 - 出口 IP 国家 ↔ 语言。
navigator.language、navigator.languages和Accept-Language请求头都应与国家相符。Camoufox 会自动让请求头和navigator保持同步。如果你传入locale=,请传带地区的完整语言区域("de-DE"而不是"de"):项目警告说,缺失的地区会被自动生成,“如果你的 IP 与语言区域的地区不符,可能引起怀疑”。 - WebRTC ↔ 出口 IP。WebRTC 可能绕过代理,暴露你真实的本地或公网地址。启用
geoip后,Camoufox 会在协议层把 WebRTC 的 IPv4 伪装成出口 IP,并关闭 IPv6 DNS。建议保持 WebRTC 开启并伪装,而不是屏蔽,因为完全没有 WebRTC 的桌面 Firefox 并不常见。 - 地理定位 API ↔ IP。Camoufox 用 GeoIP 查询结果填充经纬度,并设置权限偏好,使
navigator.permissions.query({name: "geolocation"})始终返回 "granted",与它提供的位置保持一致。不要在config里手动设置地理位置,库的警告写道,这“如果目标地理位置与 IP 不符,可能导致被检测”。 - 操作系统 ↔ 字体 ↔ GPU。生成器基于真实流量的统计模型取样,一致性检查会剔除不可能的组合,例如 Windows 的 User-Agent 搭配 Apple M1 GPU。避免使用
custom_fonts_only=True,webgl_config也只传模型在该操作系统上见过的组合(其他组合会抛出ValueError)。 - User-Agent:别动它。手动设置
User-Agent或navigator字段,是让网络层和 JavaScript 层互相矛盾的最快方式。库对这两种做法都有警告。 - IP 类型 ↔ 声称的设备。生成的消费级台式机出现在托管服务商的 ASN 上,无论指纹多好都是自相矛盾的组合。住宅(或 ISP)IP 的价值正体现在这里。服务器端如何综合这些信号,可参阅我们的浏览器指纹识别解析。
- 每个会话一个身份。Cookie、IP 和指纹要么一起变,要么都不变。旧 Cookie 出现在新 IP、新 GPU 上,比稳定的会话或全新的会话都更不像真人。
Camoufox、Patchright 还是 nodriver:怎么选
先按引擎选。如果目标站点的流量以 Chrome 为主,或者会检查 V8 行为,就用 Chromium 系工具。如果你需要深度的指纹轮换又不想写 JavaScript 补丁,并且可以接受 Firefox 流量,就用 Camoufox。下表总结了截至 2026 年 10 月的取舍。
| Camoufox | Patchright | nodriver | |
|---|---|---|---|
| 引擎 | 打过补丁的 Firefox(Gecko + SpiderMonkey) | Chromium / Chrome(浏览器本身未修改) | 你本机安装的 Chrome、Chromium、Edge 或 Brave |
| 控制协议 | Juggler(已打补丁,与页面隔离) | CDP,通过隔离 world 避免调用 Runtime.enable | 直接使用 CDP,不用 WebDriver |
| API | Playwright(Python、JS/TS) | 可直接替换 Playwright(Python、Node,社区版 .NET) | 自有的异步 Python API |
| TLS 指纹来源 | Firefox 自带的 NSS 协议栈,即 Firefox 的 ClientHello | 真实 Chrome 的 BoringSSL,尤其是使用 channel="chrome" 时 | 真实 Chrome 的 BoringSSL |
| 指纹轮换 | 内置,每次启动在 C++ 层生成 | 无。推荐使用不注入任何内容的真实 Chrome | 没有内置 |
| 维护状态(2026 年 10 月) | 已恢复活跃。2026 年 9 月发布稳定版 0.5.6,但 2025 年 3 月至 2026 年 1 月之间没有稳定版 | 跟随 Playwright。v1.63.0 驱动于 2026 年 9 月发布 | PyPI 最新版本为 0.50.3,发布于 2026 年 5 月 |
| 典型失败原因 | 针对 Firefox 的额外审查、只有 Chrome 能通过的引擎检查、被厂商发现并加入检测规则的指纹不一致 | Console API 被禁用、仅限 Chromium、通用的无头与行为信号依然有效 | 主 world 中的执行可被观察到、不管理指纹、API 覆盖面小于 Playwright |
TLS 这一行比看上去更重要。三者都使用真实浏览器的网络协议栈,因此都不会出现 Python requests 自称 Chrome 时那种不匹配。但 Camoufox 永远呈现 Firefox 的握手。如果站点的模型预期大部分流量是 Chrome 形态的 TLS,请参阅我们的 TLS 指纹识别解析,了解 JA3/JA4 如何用于这类画像。
坦率说说局限
Camoufox 擅长的是一件事:无需 JavaScript 补丁、自洽且可轮换的 Firefox 身份。它也有实实在在的代价。
Firefox 只占很小一部分流量
根据 StatCounter 的数据,2026 年 9 月 Firefox 约占全球桌面浏览量的 6.1%,Chrome 约为 65%。群体越小越容易建模,其中的任何异常也越显眼。有些站点更倾向于对非 Chromium 浏览器发起挑战。你的目标站点是否如此,只有用自己的流量测试过才知道。
它无法冒充 Chrome
README 说得很直白:Camoufox“并不完全支持注入 Chromium 指纹”,并且有些 WAF“会检测 Spidermonkey 引擎的行为,而这是不可能伪造的”。如果站点非 Chrome 不可,任何 Camoufox 配置都帮不了你。
维护时断时续
发布历史能看出这段空白。暂停前的最后一个稳定构建是 2025 年 3 月 15 日的 v135.0.1-beta.24。原作者暂停了开发,除了偶尔的社区提交,直到 2026 年 1 月的 Firefox 146 测试版之前都没有新版本。随后 README 将 Clover Labs 列为官方维护方。此后项目进展很快:5 月发布 Firefox 150 构建,7 月起发布 Firefox 152 稳定构建,9 月推出官方 TypeScript 启动器,月底又有了 Firefox 156 预发布版。README 至今仍保留警告:“本项目仍在开发中,可能不适合稳定的生产环境使用”。请锁定版本,升级前先测试。
指纹是个移动靶
项目公开承认,反爬虫厂商会“一遍又一遍地测试 Camoufox,只为找到哪怕 1 处独特的不一致”,然后针对它添加检测。拟人化光标“在足够精细的分析下仍可能被识别”。C++ 层的伪装消除了一整类特征,但并不能让你永远不被发现。
资源开销
项目称其精简构建运行时约占 200 MB,内存占用低于原版 Firefox。这是项目方给出的数字,不是我们测的,你的页面还会在此基础上增加占用。说到底,每个身份仍是一个完整的浏览器。请按每个并发会话一个浏览器来规划,而不是让多个 context 共享同一个指纹;不需要 JavaScript 的接口则用普通 HTTP 客户端请求。
Camoufox 解决不了的问题
- IP 信誉。被标记的住宅 IP 依然是被标记的。使用出口之前先测试,例如用我们的免费代理检测工具。
- 速率限制与行为。每分钟数百条一模一样的访问路径,不管指纹如何,看起来都是自动化。
- 验证码、登录与访问规则。Camoufox 并不赋予你采集任何数据的许可。请遵守 robots.txt 和站点条款,不要触碰你无权访问的认证后数据,并且即便是公开可见的个人数据,也要按 GDPR/CCPA 的监管要求对待。
稳妥的上线步骤
从一个国家、一个粘性会话开始。记录每次启动的一致性检查输出,并在决定使用哪个引擎之前,在同一目标上与 Patchright 的封锁率基线做对比。如果 Camoufox 胜出,就通过增加使用新会话 ID 的浏览器来扩展,而不是让多个会话共用一个浏览器。如果它在明显偏好 Chrome 的站点上落败,上面的表格会告诉你下一步该往哪里走。住宅网关对这三个工具的用法完全相同。国家代码和套餐选项见地区覆盖和住宅代理页面。






