用本地 API 自动化浏览器配置文件

通过脚本启动配置文件,获得调试端点,并让 Playwright 或 Puppeteer 连接到一个已经带有身份和代理的浏览器。
自动化指纹浏览器通常被说成是一道难题。其实并不难,前提是工具交给你的恰好是你的自动化库本来就会用的那样东西:调试端点。
整体思路
PowerOps 运行着一个绑定在回环地址上的 HTTP API。你的脚本请求它启动一个配置文件;它会带着该配置文件的身份、存储和代理启动浏览器,并返回正在运行的浏览器的 WebSocket 端点。你的脚本再用 Playwright、Puppeteer 或任何支持 DevTools 协议的工具连接到这个端点。
自动化库完全不需要知道指纹是什么。等它连接上的时候,环境已经就绪。
启动配置文件
curl -s -H "Authorization: Bearer $POWEROPS_API_KEY" \
http://127.0.0.1:50326/status
除状态检查外,每个路由都需要 Bearer 密钥。启动浏览器会返回供你连接的端点:
curl -s -X POST \
-H "Authorization: Bearer $POWEROPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profileId": "..."}' \
http://127.0.0.1:50326/browser/start
连接你的库
import { chromium } from "playwright";
const res = await fetch("http://127.0.0.1:50326/browser/start", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.POWEROPS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ profileId }),
});
const { ws } = await res.json();
// The profile's identity, storage and proxy are already in place.
const browser = await chromium.connectOverCDP(ws);
const [context] = browser.contexts();
const page = context.pages()[0] ?? await context.newPage();
await page.goto("https://example.com");
最关键的是那行注释。你的脚本里没有任何指纹配置,因为配置环境不是脚本的职责。它属于配置文件,无论配置文件是由人点击某一行打开的,还是由凌晨三点的定时任务打开的,环境都保持不变。
API 涵盖的内容
- 状态路由是健康检查,也是唯一不需要密钥的路由。
- 浏览器路由用于启动、停止和查询当前正在运行的浏览器。
- 配置文件路由用于创建、更新、查询和删除配置文件。
- 代理路由用于管理代理库和分配路由。
- 分组路由用于批量整理配置文件。
- 扩展路由用于导入和分配扩展。
如何保持仅限本地
一个驱动着已登录账号的浏览器的 API,有必要交代一下它的边界。
- 它绑定在 127.0.0.1 上。没有任何设置能让它监听其他网络接口。
- 除状态检查外,每个路由都需要 Bearer 密钥。
- 它会校验 Host 头,并且不发送任何 CORS 头,因此你日常浏览器中打开的网页无法访问它。
- 机密信息是只写的:配置文件密码、双重验证密钥和代理密码绝不会由任何查询路由返回。
值得照搬的模式
查询某个分组中的配置文件,逐个启动,完成工作后停止。每次只运行几个,不要一次全开。限制来自你自己机器的内存,因为每个配置文件都是一个真实的浏览器进程。
const { profiles } = await api("/profiles?groupId=" + groupId);
for (const batch of chunk(profiles, 5)) {
await Promise.all(batch.map(async (profile) => {
const { ws } = await api("/browser/start", { profileId: profile.id });
try {
await doTheWork(ws);
} finally {
await api("/browser/stop", { profileId: profile.id });
}
}));
}
在 `finally` 中停止配置文件,比看上去重要得多:正常关闭才会把浏览器状态写出,而在会话中途被强行结束的配置文件,可能会丢失刚刚建立的会话。
