开放接口文档
启元指纹浏览器 · 本地客户端开放 API · v1
认证流程
只需在启动客户端时传入 --run_mode=api --app_id=xxx --app_secret=xxx,
客户端自动完成身份认证,后续所有接口调用均无需额外传递凭证。
AppID 和 AppSecret 从「开发者中心」页面获取。
建立连接
开放接口是通过Socket.IO协议进行通讯的,客户端启动后,Socket.IO 服务默认监听在 http://127.0.0.1:9001(可通过 --port 参数修改)。
启动命令
Qiyuan.exe --run_mode=api --port=9001 --app_id=your_app_id --app_secret=your_app_secret
接入示例(Node.js)
// npm install socket.io-client const { io } = require('socket.io-client'); const socket = io('http://127.0.0.1:9001'); socket.on('connect', () => { console.log('已连接到启元客户端'); }); socket.emit('env:list', { page: 1, page_size: 10 }, (res) => { if (res.success) console.log(res.data.items); else console.error(res.error); });
环境接口 Browser
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | number | 可选 | 页码,默认 1 |
| page_size | number | 可选 | 每页数量,默认 20,最大 100 |
| keyword | string | 可选 | 按环境名称模糊搜索 |
响应 data
{
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5,
"items": [
{
"code": "a1b2c3d4...", // string 环境唯一标识,后续操作均使用此字段
"name": "测试账号-01", // string 环境名称
"browser_version": "138.0.7204.184", // string 内核版本号,null 表示未配置
"platform": "Win32", // string Win32 / MacIntel / Linux x86_64
"user_agent": "Mozilla/5.0 ...", // string User-Agent 字符串
"proxy_ip_code": "1716523...", // string 绑定代理的唯一标识,未绑定为 null
"remark": "备注信息", // string 备注
"tag_ids": [1, 2], // number[] 标签 ID 列表
"open_home_page": true, // boolean 是否打开首页
"status": "stopped", // string running | stopped
"debug_port": null, // number CDP 调试端口,running 时有值,否则 null
"create_time": "2024-01-01T00:00:00",
"update_time": "2024-06-01T12:00:00"
}
]
}
基础信息字段
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| name | string | 必填 | — | 环境名称 |
| platform | string | 可选 | Win32 | 操作系统。可选值:Win32 / MacIntel / Linux x86_64 |
| browser_version | string | 可选 | 145.0.7632.109(最新) | 完整内核版本号。不填自动取最新版本。可选值:145.0.7632.109 / 139.0.7258.67 / 138.0.7204.184 |
| user_agent | string | 可选 | 自动生成 | User-Agent。不填时根据 platform + browser_version 自动生成(UA 随版本变化) |
| proxy_ip_code | string | 可选 | 绑定代理的唯一标识(来自 proxy:list 的 code 字段) | |
| open_home_page | boolean | 可选 | false | 是否打开首页 |
| enable_tabs | boolean | 可选 | false | 是否启用多标签页 |
| tabs | string | 可选 | "" | 标签页 URL,多个用换行分隔(enable_tabs=true 时生效) |
| sync_user_info | boolean | 可选 | false | 是否开启云端用户信息同步(账号数据云备份) |
| cookie | string | 可选 | "" | 初始 Cookie 内容 |
| launch_args | string | 可选 | "" | 额外 Chrome 启动参数,空格分隔,如 --disable-gpu --no-sandbox |
| remark | string | 可选 | "" | 备注 |
| tag_ids | number[] | 可选 | [] | 标签 ID 列表 |
指纹字段
所有指纹字段均为可选,未传时使用后端默认值。
| 字段 | 类型 | 默认值 | 说明 / 可选值 |
|---|---|---|---|
| webrtc | string | disabled | ip 基于IP | real 真实 | disabled 禁用 | transform_google 转发 |
| webgl | string | real | real 真实 | custom 自定义(需同时提供 webgl_vendor 和 webgl_renderer) |
| webgl_vendor | string | — | webgl=custom 时必填。厂商名,如 Intel Inc. / NVIDIA Corporation / AMD / Apple Inc. |
| webgl_renderer | string | — | webgl=custom 时必填。渲染器名,如 Intel(R) UHD Graphics 630 / NVIDIA GeForce RTX 4090 |
| webgpu | string | basegl | basegl 基于WebGL | real 真实 | custom 自定义(需提供 webgpu_vendor/architecture/device/description) |
| webgpu_vendor | string | — | webgpu=custom 时使用,如 intel / nvidia / amd / apple |
| webgpu_architecture | string | — | 如 common-shader-cores / rdna-3 / apple-gpu |
| webgpu_device | string | — | 如 integrated-gpu / discrete-gpu |
| webgpu_description | string | — | 如 NVIDIA GeForce RTX 4090 / Intel Iris Xe Graphics |
| timezone | string | ip | ip 基于IP | real 真实 | custom 自定义(需提供 timezone_value) |
| timezone_value | string | — | timezone=custom 时使用,IANA 时区格式,如 Asia/Shanghai / America/New_York / Europe/London |
| geo_location | string | ip | ip 基于IP | real 真实 | custom 自定义(需提供 longitude 和 latitude) |
| longitude | string | — | geo_location=custom 时使用,经度,如 116.3 |
| latitude | string | — | geo_location=custom 时使用,纬度,如 39.9 |
| language | string | ip | ip 基于IP | real 真实 | custom 自定义(需提供 languages 数组) |
| languages | string[] | — | language=custom 时使用,语言代码数组,如 ["zh-CN","en-US"]。可用值:zh-CN / zh-TW / en-US / en-GB / ja-JP / ko-KR / fr-FR / de-DE / es-ES / pt-BR / ru-RU 等 |
| ui_language | string | language | language 跟随语言 | real 真实 | custom 自定义(需提供 ui_language_value) |
| ui_language_value | string | — | ui_language=custom 时使用,单个语言代码,如 zh-CN |
| screen_resolution | string | real | real 真实 | custom 自定义(需提供 screen_resolution_value) |
| screen_resolution_value | string | — | screen_resolution=custom 时使用,格式 宽|高,可选:1920|1080 / 2560|1440 / 3840|2160 / 1366|768 / 1440|900 / 1536|864 / 1280|720 / 2560|1080 等 |
| font | string | random | disabled 关闭(值固定为0) | random 随机(服务端生成 -2~2 整数偏移量) |
| canvas | string | random | disabled 关闭 | random 随机(服务端生成 0~1 浮点噪点,2位小数) |
| audio | string | random | disabled 关闭 | random 随机(服务端生成 0~99 整数噪点) |
| client_rects | string | random | disabled 关闭 | random 随机(服务端生成 0~0.00001 浮点偏移,6位小数) |
| speech_voices | boolean | true | true 开启 | false 关闭语音合成设备伪装 |
| media_devices | string | random | disabled 关闭(null) | random 随机(服务端生成5个随机媒体设备ID) |
| cpu_cores | string | real | real 使用真实值 | 2 / 4 / 6 / 8 / 10 / 12 / 16 / 20 / 24 / 32 |
| memory_gb | string | real | real 使用真实值 | 2 / 4 / 8 / 16 / 32 / 64 / 128(单位 GB) |
| tls | string | enabled | disabled 关闭 | enabled 启用(不传 tls_features 则默认启用全部特征) |
| tls_features | string[] | — | tls=enabled 时可选,不填则启用全部。可选值(多选)::!aPSK 禁用PSK认证 / :!kRSA 禁用RSA密钥交换 / :!ECDSA 禁用ECDSA证书 / :!ECDSA+SHA1 / :!3DES 禁用3DES加密 |
响应 data
{
"code": "a1b2c3..." // string 新建环境的唯一标识(后续所有操作使用此字段)
}
示例
# 最简调用(版本默认最新,UA 自动生成,指纹全部随机) call("env:create", {"name": "账号01"}) # 完整指纹示例 call("env:create", { "name": "账号02", "platform": "Win32", "browser_version": "145.0.7632.109", # 不填则自动取最新 "proxy_ip_code": "PROXY_CODE", "webrtc": "disabled", "webgl": "custom", "webgl_vendor": "NVIDIA Corporation", "webgl_renderer": "NVIDIA GeForce RTX 4090", "webgpu": "basegl", # 跟随 WebGL "timezone": "custom", "timezone_value": "Asia/Shanghai", "geo_location": "custom", "longitude": "116.3", "latitude": "39.9", "language": "custom", "languages": ["zh-CN", "en-US"], "screen_resolution": "custom", "screen_resolution_value": "1920|1080", "font": "random", "canvas": "random", "audio": "random", "client_rects": "random", "speech_voices": True, "media_devices": "random", "cpu_cores": "8", "memory_gb": "16", "tls": "enabled", # 不填 tls_features 则默认启用全部 "enable_tabs": True, "tabs": "https://www.google.com\nhttps://www.example.com", "sync_user_info": False, "remark": "由脚本创建", })
支持与 env:create 相同的所有字段(code 必填,其余字段只传需要修改的)。未传的字段保持不变。
必填字段
| 字段 | 类型 | 说明 |
|---|---|---|
| code | string | 环境唯一标识 |
可修改字段
与 env:create 入参完全一致(除 name 不再必填),包括所有基础信息字段和指纹字段。
特别说明:若修改了 platform 或 browser_version 但未传 user_agent,系统自动重新生成匹配的 UA。
响应
{ "success": true }
示例
# 只修改备注 call("env:update", {"code": env_code, "remark": "新备注"}) # 切换代理并修改 WebRTC 策略 call("env:update", { "code": env_code, "proxy_ip_code": "NEW_PROXY_CODE", "webrtc": "disabled", }) # 修改版本(UA 自动跟随更新) call("env:update", {"code": env_code, "browser_version": "145.0.7632.109"})
一键随机重新生成环境的指纹数据,逻辑与客户端界面的"随机指纹"按钮完全一致。WebGL/WebGPU 按平台随机,font/canvas/audio/client_rects/media_devices 全部重新随机,时区/地理位置/语言保持基于IP策略。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应 data
{
"webgl_vendor": "NVIDIA Corporation", // 本次随机的 WebGL 厂商
"webgl_renderer": "NVIDIA GeForce RTX 4090", // 本次随机的 WebGL 渲染器
"webgpu_value": "nvidia|common-shader-cores|discrete-gpu|NVIDIA GeForce RTX 4090",
"font": -1, // -2~2 整数偏移
"canvas": 0.73, // 0~1 浮点噪点
"audio": 42, // 0~99 整数噪点
"client_rects": 0.000007, // 0~0.00001 浮点偏移
"speech_voices": true,
"media_devices": ["a3f2...", "..."] // 5个随机设备ID
}
示例
call("env:randomize_fingerprint", {"code": env_code})
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true }
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
| headless | boolean | 可选 | 是否无头模式,默认 false。设为 true 时浏览器不显示窗口,适合自动化场景 |
| args | string[] | 可选 | 追加给 Chrome 的额外启动参数,如 ["--kiosk", "--blink-settings=imagesEnabled=false"] |
响应 data
{
"pid": 12345, // number 浏览器进程 PID
"debug_port": 19222 // number CDP 调试端口(19222-19999 范围内唯一分配)
}
通过调试端口接入自动化框架
# Playwright (Python) from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.connect_over_cdp('http://127.0.0.1:19222') # Selenium (Python) from selenium import webdriver options = webdriver.ChromeOptions() options.add_experimental_option('debuggerAddress', '127.0.0.1:19222') driver = webdriver.Chrome(options=options)
每次 env:open 都会分配唯一调试端口,浏览器关闭后端口自动释放并可被复用。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true } // 浏览器未运行时返回 success: false
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应 data
{
"code": "a1b2c3...", // string 环境唯一标识
"status": "running", // string running | stopped
"pid": 12345, // number 进程 PID,stopped 时为 null
"debug_port": 19222 // number CDP 调试端口,stopped 时为 null
}
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true }
清空操作会删除本地 %appdata%\qiyuan\user_data\{code} 目录,若该环境开启了云同步则同时删除服务器备份。
代理接口 Proxy
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | number | 可选 | 页码,默认 1 |
| page_size | number | 可选 | 每页数量,默认 20,最大 100 |
| keyword | string | 可选 | 按名称或地址模糊搜索 |
响应 data
{
"total": 50,
"page": 1,
"page_size": 20,
"total_pages": 3,
"items": [
{
"code": "1716523200abc", // string 代理唯一标识(用于修改 / 删除 / 绑定到环境)
"proxy_name": "美国-01", // string 代理名称
"proxy_type": "socks5", // string http | https | socks5
"proxy_addr": "1.2.3.4", // string 代理服务器地址
"proxy_port": 1080, // number 代理端口
"username": "user", // string 认证用户名,无则 null
"create_time": "2024-01-01T00:00:00",
"update_time": "2024-06-01T12:00:00"
}
]
}
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| proxy_name | string | 必填 | 代理名称 |
| proxy_type | string | 必填 | 代理类型:http / https / socks5 |
| proxy_addr | string | 必填 | 代理服务器地址(IP 或域名) |
| proxy_port | number | 必填 | 代理端口(1-65535) |
| username | string | 可选 | 认证用户名 |
| password | string | 可选 | 认证密码 |
响应 data
{
"code": "1716523200abc" // string 新建代理的唯一标识(用于绑定到环境)
}
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 代理唯一标识 |
| proxy_name | string | 可选 | 新的代理名称 |
| proxy_type | string | 可选 | 新的代理类型 |
| proxy_addr | string | 可选 | 新的代理地址 |
| proxy_port | number | 可选 | 新的代理端口 |
| username | string | 可选 | 新的认证用户名 |
| password | string | 可选 | 新的认证密码 |
响应
{ "success": true }
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 代理唯一标识 |
响应
{ "success": true }
统一响应格式
所有接口均通过 Socket.IO 的 ACK 回调函数返回结果:
// 成功 { "success": true, "data": { /* 业务数据 */ } } // 失败 { "success": false, "error": "错误描述" }
部分接口成功时不返回 data 字段(如 delete、close),只需判断 success 即可。
使用示例
# 依赖: pip install "python-socketio[client]" playwright # playwright install chromium import socketio, time SERVER_URL = "http://127.0.0.1:9001" sio = socketio.Client() def call(event, data=None): result, done = {}, [False] def cb(res): result.update(res); done[0] = True sio.emit(event, data or {}, callback=cb) t = 30 while not done[0] and t > 0: time.sleep(0.1); t -= 0.1 return result print("[连接] 正在连接到启元客户端...") sio.connect(SERVER_URL) print("[连接] 已连接") # ── 新增代理 ────────────────────────────────────────────────────────────── print("[代理] 正在新增代理...") res = call("proxy:create", { "proxy_name": "美国住宅-01", "proxy_type": "socks5", "proxy_addr": "1.2.3.4", "proxy_port": 1080, "username": "user", "password": "pass", }) print("[代理] 结果:", res) proxy_code = res["data"]["code"] print(f"[代理] code={proxy_code}") # ── 新增环境(指纹字段不传则自动随机)──────────────────────────────────── print("[环境] 正在新增环境...") res = call("env:create", { "name": "账号-01", # proxy_ip_code 暂不绑定,如需绑定传入: "proxy_ip_code": proxy_code "timezone": "custom", "timezone_value": "Asia/Shanghai", "geo_location": "custom", "longitude": "116.3", "latitude": "39.9", "language": "custom", "languages": ["zh-CN", "en-US"], "cpu_cores": "8", "memory_gb": "16", }) print("[环境] 结果:", res) env_code = res["data"]["code"] print(f"[环境] code={env_code}") # ── 刷新指纹 ─────────────────────────────────────────────────────────────── print("[指纹] 正在随机刷新指纹...") res = call("env:randomize_fingerprint", {"code": env_code}) print("[指纹] 结果:", res["data"]) # ── 打开浏览器(headless=False 显示窗口)───────────────────────────────── print("[浏览器] 正在打开浏览器...") res = call("env:open", {"code": env_code, "headless": False}) print("[浏览器] 结果:", res) debug_port = res["data"]["debug_port"] print(f"[浏览器] 调试端口={debug_port}") # ── 接入 Playwright ──────────────────────────────────────────────────────── print("[Playwright] 正在连接...") try: from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.connect_over_cdp(f"http://127.0.0.1:{debug_port}") page = browser.contexts[0].new_page() page.goto("https://www.baidu.com") title = page.title() print(f"[Playwright] 页面标题={title}") except Exception as e: # ===================== 发生异常:及时打印 + 抛出(不吞错) print(f"[错误] Playwright 执行失败: {str(e)}") raise # 关键:抛出异常,让外部能捕获到,实现"及时报错" finally: # ===================== 无论成功/失败/崩溃,100% 执行 print(f"[批量] 获取浏览器状态 {env_code}...") r = call("env:status", {"code": env_code}) print(f"状态结果={r}") print("[关闭] 正在执行兜底关闭...") call("env:close", {"code": env_code}) print("[关闭] 完成") # ── 接入 Selenium ────────────────────────────────────────────────────────── # pip install selenium # from selenium import webdriver # from selenium.webdriver.chrome.options import Options # from selenium.webdriver.chrome.service import Service # options = Options() # options.add_experimental_option("debuggerAddress", f"127.0.0.1:{debug_port}") # # driver = webdriver.Chrome(options=options) # # chromedriver 下载地址对应浏览器版本(比如 # # 138.x):https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.184/win64/chromedriver-win64.zip,选对应版本的 win64 chromedriver 下载即可 # service = Service(executable_path=r"D:\webdrivers\chromedriver138.exe") # driver = webdriver.Chrome(service=service, options=options) # driver.get("https://www.example.com") # print("Selenium 页面标题:", driver.title) # driver.quit() # ── 批量查询环境列表 ─────────────────────────────────────────────────────── print("[批量] 查询环境列表...") res = call("env:list", {"page": 1, "page_size": 10}) for env in res["data"]["items"]: print(f"环境结果={env}") sio.disconnect() print("[连接] 已断开")
// 依赖: npm install socket.io-client playwright const { io } = require("socket.io-client"); const socket = io("http://127.0.0.1:9001"); const call = (event, data = {}) => new Promise((resolve) => socket.emit(event, data, resolve)); socket.on("connect", async () => { console.log("[连接] 已连接到启元客户端"); // ── 新增代理 ────────────────────────────────────────────────────────── console.log("[代理] 正在新增代理..."); let res = await call("proxy:create", { proxy_name: "美国住宅-01", proxy_type: "socks5", proxy_addr: "1.2.3.4", proxy_port: 1080, username: "user", password: "pass", }); console.log("[代理] 结果:", res); const proxyCode = res.data.code; console.log("[代理] code=", proxyCode); // ── 新增环境 ────────────────────────────────────────────────────────── console.log("[环境] 正在新增环境..."); res = await call("env:create", { name: "账号-01", // proxy_ip_code 暂不绑定,如需绑定传入: proxy_ip_code: proxyCode timezone: "custom", timezone_value: "Asia/Shanghai", geo_location: "custom", longitude: "116.3", latitude: "39.9", language: "custom", languages: ["zh-CN", "en-US"], cpu_cores: "8", memory_gb: "16", }); console.log("[环境] 结果:", res); const envCode = res.data.code; console.log("[环境] code=", envCode); // ── 刷新指纹 ────────────────────────────────────────────────────────── console.log("[指纹] 正在随机刷新指纹..."); res = await call("env:randomize_fingerprint", { code: envCode }); console.log("[指纹] 结果:", res.data); // ── 打开浏览器 ──────────────────────────────────────────────────────── console.log("[浏览器] 正在打开浏览器..."); res = await call("env:open", { code: envCode, headless: true }); console.log("[浏览器] 结果:", res); const debugPort = res.data.debug_port; console.log("[浏览器] 调试端口=", debugPort); // ── 接入 Playwright ─────────────────────────────────────── console.log("[Playwright] 正在连接..."); const { chromium } = require("playwright"); let browser = null; // 提升作用域,finally 里能访问 try { // 1. 连接浏览器 browser = await chromium.connectOverCDP(`http://127.0.0.1:${debugPort}`); // 2. 获取页面 const page = browser.contexts()[0].pages()[0]; // 3. 访问网页 await page.goto("https://www.example.com"); const title = await page.title(); console.log("[Playwright] 页面标题=", title); } catch (err) { // 出错立即抛出,不吞错,保证及时报错 console.error("[Playwright] 执行失败:", err.message); throw err; // 关键:抛出错误,外部能捕获 } finally { // ======================= 无论成功/失败/崩溃,100% 执行 ======================= console.log("[兜底] 开始执行统一关闭流程..."); try { // 1. 关闭 Playwright 浏览器 if (browser) { await browser.close().catch(() => {}); // 关闭失败也不阻塞 console.log("[Playwright] 已安全关闭"); } // 2. 执行 env:close 兜底 await call("env:close", { code: envCode }).catch(() => {}); console.log("[关闭] env:close 已执行"); // 3. 断开 socket if (socket) { socket.disconnect(); console.log("[连接] socket 已断开"); } } catch (cleanupErr) { console.warn("[兜底] 关闭流程出现轻微异常:", cleanupErr.message); } console.log("[兜底] 所有收尾任务执行完成"); } });
// Maven 依赖: // io.socket:socket.io-client:2.1.0 // org.json:json:20231013 import io.socket.client.IO; import io.socket.client.Socket; import org.json.JSONArray; import org.json.JSONObject; import java.util.concurrent.CountDownLatch; public class QiyuanDemo { static Socket socket; static JSONObject call(String event, JSONObject data) throws Exception { JSONObject[] result = {null}; CountDownLatch latch = new CountDownLatch(1); socket.emit(event, data, (Object... args) -> { result[0] = new JSONObject(args[0].toString()); latch.countDown(); }); latch.await(); return result[0]; } public static void main(String[] args) throws Exception { System.out.println("[连接] 正在连接到启元客户端..."); socket = IO.socket("http://127.0.0.1:9001"); socket.connect(); Thread.sleep(1000); System.out.println("[连接] 已连接"); // ── 新增代理 ────────────────────────────────────────────────── System.out.println("[代理] 正在新增代理..."); JSONObject proxyRes = call("proxy:create", new JSONObject() .put("proxy_name", "美国住宅-01").put("proxy_type", "socks5") .put("proxy_addr", "1.2.3.4").put("proxy_port", 1080) .put("username", "user").put("password", "pass")); System.out.println("[代理] 结果: " + proxyRes); String proxyCode = proxyRes.getJSONObject("data").getString("code"); System.out.println("[代理] code=" + proxyCode); // ── 新增环境 ────────────────────────────────────────────────── System.out.println("[环境] 正在新增环境..."); JSONObject envRes = call("env:create", new JSONObject() .put("name", "账号-01") // .put("proxy_ip_code", proxyCode) // 暂不绑定,如需绑定取消注释 .put("timezone", "custom").put("timezone_value", "Asia/Shanghai") .put("geo_location", "custom").put("longitude", "116.3").put("latitude", "39.9") .put("language", "custom").put("languages", new JSONArray().put("zh-CN").put("en-US")) .put("cpu_cores", "8").put("memory_gb", "16")); System.out.println("[环境] 结果: " + envRes); String envCode = envRes.getJSONObject("data").getString("code"); System.out.println("[环境] code=" + envCode); // ── 刷新指纹 ────────────────────────────────────────────────── System.out.println("[指纹] 正在随机刷新指纹..."); JSONObject fpRes = call("env:randomize_fingerprint", new JSONObject().put("code", envCode)); System.out.println("[指纹] 结果: " + fpRes.opt("data")); // ── 打开浏览器 ──────────────────────────────────────────────── System.out.println("[浏览器] 正在打开浏览器..."); JSONObject openRes = call("env:open", new JSONObject() .put("code", envCode).put("headless", true)); System.out.println("[浏览器] 结果: " + openRes); int debugPort = openRes.getJSONObject("data").getInt("debug_port"); System.out.println("[浏览器] 调试端口=" + debugPort); // ── 接入 Playwright (com.microsoft.playwright) ──────────────── // System.out.println("[Playwright] 正在连接..."); // Playwright pw = Playwright.create(); // Browser browser = pw.chromium() // .connectOverCDP("http://127.0.0.1:" + debugPort); // Page page = browser.contexts().get(0).newPage(); // page.navigate("https://www.example.com"); // System.out.println("[Playwright] 标题=" + page.title()); // ── 关闭浏览器 ──────────────────────────────────────────────── System.out.println("[关闭] 正在关闭浏览器..."); call("env:close", new JSONObject().put("code", envCode)); System.out.println("[关闭] 完成"); socket.disconnect(); System.out.println("[连接] 已断开"); } }