Canvas 桥接
在远程的真实 GPU 上渲染 canvas 和 WebGL,让页面回读的像素与渲染主机实际拥有的 GPU 保持一致——请把 profile 的 GPU 字符串设置为与之匹配。这是一项实验性功能,需主动开启——不设置 --canvas-bridge-url 时,Clearcote 完全在本地渲染,与以往完全相同。
为什么需要它
Clearcote 在主机实际拥有的 GPU 上渲染 canvas/WebGL。如果某个 profile 声称的 GPU 与主机不同,那些把渲染像素与所声称硬件进行比对的严格检测(指纹浏览器检测 / 浏览器篡改检测)就可能发现这种不匹配——你无法靠软件让一块 GPU 输出另一块 GPU 的精确像素。canvas 桥接消除了这种不匹配:它不是在本地渲染、只伪装 GPU 字符串,而是把 canvas/WebGL 操作转发到拥有你想呈现的那块 GPU 的远程主机,并返回该主机的真实像素。由于转发的是操作(而不是一个固定的预录图像库),它能处理大多数动态生成的 canvas,而不仅仅是已知的探测脚本。
工作原理
回读 API——getImageData、toDataURL、readPixels 和 measureText——返回的是桥接主机的真实像素;在桥接路径上,本地的 farbling 噪声会被跳过(桥接像素就是基准真值)。传输层是一个 WebSocket,承载紧凑的二进制消息流。像素来自渲染浏览器所用的那块 GPU。
clearcote (your automation host) bridge host (real GPU)
+-----------------------------+ +-------------------------+
| page: getImageData / | ops --> | render browser |
| toDataURL / readPixels | | renders on the real GPU,|
| CanvasBridgeClient <-- pixels ---------| reads back the pixels |
+-----------------------------+ +-------------------------+前提条件
- 一台渲染主机——任何拥有你想呈现的 GPU 的机器(Windows 身份画像就配 Windows GPU)。它的 GPU 会成为你的 profile 所呈现的 canvas 身份,所以请选择与你想展示的身份画像(persona)相匹配的硬件(要呈现 NVIDIA 就用一台 NVIDIA 机器,以此类推)。把服务器的
--backend cdp指向你在该机器上运行的普通 Chrome(推荐),或者使用--backend local配合 Clearcote 二进制。 - 自动化主机与桥接主机之间的一条私有网络链路。桥接使用明文 WebSocket(
ws://)——务必通过私有网络或加密隧道(Tailscale、WireGuard 或 SSH 端口转发)运行。切勿把桥接端口暴露在公网上。
配置步骤
1. 在真实 GPU 主机上启动渲染服务器。这是一个小型 Python 协调程序,它驱动一个无头浏览器,并在其真实 canvas 上重放转发过来的操作,因此返回的像素与该 GPU 实际生成的完全相同。渲染主机的真实 GPU 就成为 canvas/WebGL 身份。使用 --backend cdp 时,服务器启动时会打印渲染 GPU 的 renderer 字符串(render GPU='ANGLE (…)')——记下它,第 3 步要用。使用 --backend local 时,则改为从同一台机器上的普通 Chrome 读取这些字符串。
pip install playwright # one-time (no browser download needed for CDP)
# a regular Chrome on the GPU host, started with --remote-debugging-port=9222
# --user-data-dir=<a separate folder> (Chrome ignores the port on its default profile);
# its CDP URL is webSocketDebuggerUrl from http://127.0.0.1:9222/json/version
python tools/canvas-bridge-server/server.py \
--backend cdp \
--cdp-url ws://127.0.0.1:9222/devtools/browser/... \
--port 8443
# Or let the server launch a Clearcote binary itself:
# python tools/canvas-bridge-server/server.py \
# --backend local \
# --chrome /path/to/clearcote/chrome.exe \
# --port 84432. 建立隧道。ws:// 未加密——把两台主机放进同一个 Tailscale/WireGuard 网络,或者通过 SSH 转发端口。服务器默认绑定 localhost,所以在 Tailscale/WireGuard 上要用 --host <that interface's IP> 启动它;下面的 SSH 方式则无需改动即可使用:
ssh -N -L 8443:localhost:8443 user@bridge-host
# the bridge is now reachable at ws://127.0.0.1:84433. 启动客户端(即你用于自动化的 Clearcote),指向桥接地址,并带上渲染 GPU 的字符串——renderer 与服务器打印的完全一致,vendor 写成 Google Inc. (<first name in the renderer>),例如 Google Inc. (Intel)。桥接让像素与渲染 GPU 一致,这两个参数则让上报的字符串也与之一致。缺少它们,身份画像的 GPU 名称就会与桥接像素对不上:
--canvas-bridge-url=ws://127.0.0.1:8443 \
--no-sandbox \
--fingerprint=<seed> \
--fingerprint-gpu-vendor='Google Inc. (Intel)' \
--fingerprint-gpu-renderer='ANGLE (Intel, Intel(R) UHD Graphics ... D3D11)'| 参数 | 含义 |
|---|---|
| --canvas-bridge-url | 桥接端点 ws://host:port。启用桥接时必填。 |
| --canvas-bridge-auth | 可选的 user:secret HTTP Basic 凭据,适用于在服务器前面加了一层认证的部署。参考服务器不会校验这些凭据,因此访问控制请依靠私有网络或隧道。 |
| --no-sandbox | 必需——客户端从渲染进程打开桥接 socket,而沙箱会阻止这一操作。 |
| --fingerprint | 你的身份画像种子(seed)。 |
| --fingerprint-gpu-vendor / --fingerprint-gpu-renderer | 渲染 GPU 的字符串:renderer 与服务器打印的完全一致,vendor 写成 Google Inc. (<first name in the renderer>)。 |
| --canvas-bridge-mode | 按源(origin)生效的策略:off、all(默认)、allow 或 deny。 |
| --canvas-bridge-allow / --canvas-bridge-deny | 以逗号分隔的 eTLD+1 列表,供 mode=allow 或 mode=deny 使用。 |
| --canvas-bridge-fallback | 冷缓存未命中时的行为:block(默认)等待桥接返回;local 则直接提供本地像素,不会卡住。 |
通过 SDK 使用
SDK(Node、Python 和 .NET;当前版本 0.31.1)提供原生支持的 canvasBridge / canvas_bridge / CanvasBridge 选项。设置桥接 URL 后,SDK 会生成相应开关,并自动加上 --no-sandbox。在完整启动脚本中使用同样的 allow-list 策略,见示例。
const browser = await clearcote.launch({
fingerprint: "user-1",
gpuVendor: "Google Inc. (Intel)", // "Google Inc. (<first name in the renderer>)"
gpuRenderer: "ANGLE (Intel, Intel(R) UHD Graphics ... D3D11)", // exactly as the server printed it
canvasBridge: {
url: "ws://127.0.0.1:8443",
auth: "user:secret",
mode: "allow",
allow: ["example.com"],
fallback: "local",
},
});验证是否生效
- 连接成功时,客户端日志会打印
canvas-bridge: connected to <host>:<port>(需使用--enable-logging=stderr --v=1运行才能看到)。 - 打开一个会对 canvas/WebGL 表面计算哈希的页面——桥接连通时,哈希对应的是桥接主机的 GPU,而不是你的自动化主机的 GPU。快速检查:分别在启用和不启用桥接时运行同一段
canvas.toDataURL(),结果会不同。 - 如果桥接不可达,Clearcote 会记录一条警告并回退到本地渲染——桥接配置有误时会平稳降级,不会让页面出错。
注意事项与限制
- canvas 身份 = 桥接主机,而不是种子。共用同一台桥接主机的所有 profile 都共享该主机的 canvas/WebGL 哈希,因此可以通过 canvas 哈希把它们关联起来。如果需要大量无法相互关联的身份,请为每个身份组配一台桥接主机(GPU)。
- 延迟。除非
fallback设为local,否则未命中桥接缓存的像素回读就是一次阻塞式的网络往返(5 秒超时,之后回退到本地);引擎会在每次绘制后预取,因此对未变化的 canvas 重复读取像素无需等待。每次measureText调用仍是一次往返。请把桥接主机放在同一局域网/数据中心内;对延迟敏感、大量使用 canvas 的页面,不要使用桥接。 - 程序化生成的 WebGL 纹理会走桥接。以图像、2D canvas、视频、
ImageBitmap和 3D 纹理为来源时,该 canvas 会回退到本地渲染,因此结果仍然正确,只是不经过桥接。 - 客户端必须使用
--no-sandbox,且传输为明文——务必走隧道;切勿公开暴露桥接端口。
实验性功能。开源版构建自 v0.1.0-pre.12 起提供,授权版构建也已包含。权威参考文档(含完整的故障排查表)见 GitHub 上的 canvas-bridge 指南。大多数场景并不需要桥接——标准的引擎层面控制见指纹参数。