快速上手:接管候鸟浏览器环境
本章提供三种语言的完整可运行脚本,选一种您熟悉的,照着跑起来即可。核心逻辑都一样——先向 ApiServer 要 ws 地址,再用 connectOverCDP 接管候鸟浏览器。
方式一:JavaScript / Node.js 版本
创建文件 start.js:
javascript
const { chromium } = require('playwright');
const axios = require('axios');
// ============================
// 配置区域(按您的实际情况填写)
// ============================
const API_URL = 'http://127.0.0.1:8186';
const SESSION_ID = '替换为您的环境ID'; // 右键候鸟环境 → 复制环境ID
async function main() {
// ── 第一步:通知 ApiServer 开启指定候鸟环境 ──────────
console.log('⏳ 正在开启候鸟环境...');
let wsEndpoint;
try {
const response = await axios.post(`${API_URL}/api/v1/browser/start`, {
Session_ID: SESSION_ID
});
if (response.data.code !== 0) {
console.error('❌ 环境启动失败:', response.data.message);
return;
}
// ── 第二步:取出 WebSocket 地址(Playwright 专用字段)──
wsEndpoint = response.data.data.ws;
console.log('✅ 环境已开启,ws 地址:', wsEndpoint);
} catch (err) {
console.error('❌ 无法连接到 ApiServer,请确认已启动!', err.message);
return;
}
// ── 第三步:用 connectOverCDP 接管候鸟浏览器 ─────────
const browser = await chromium.connectOverCDP(wsEndpoint);
console.log('🎉 Playwright 接管成功!');
try {
// ── 第四步:获取当前上下文和页面 ────────────────────
// 候鸟环境已有一个默认上下文,直接取第一个即可
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
// ── 第五步:执行您的业务操作 ─────────────────────────
await page.goto('https://www.mbbrowser.com', { waitUntil: 'domcontentloaded' });
console.log('📄 当前页面标题:', await page.title());
// 等待 3 秒,便于肉眼观察
await page.waitForTimeout(3000);
console.log('✅ 脚本执行完毕!');
} finally {
// 断开 Playwright 连接(候鸟浏览器窗口继续保持运行)
await browser.close();
}
}
main().catch(console.error);运行:
bash
node start.js方式二:Python 版本
创建文件 start_playwright.py:
python
import requests
from playwright.sync_api import sync_playwright
# ============================
# 配置区域
# ============================
API_URL = "http://127.0.0.1:8186"
SESSION_ID = "替换为您的环境ID"
def get_ws_endpoint(session_id: str) -> str | None:
"""调用候鸟 ApiServer,开启环境并返回 ws 地址"""
print("⏳ 正在开启候鸟环境...")
try:
resp = requests.post(
f"{API_URL}/api/v1/browser/start",
json={"Session_ID": session_id},
timeout=30
)
data = resp.json()
except requests.exceptions.ConnectionError:
print("❌ 无法连接到 ApiServer!请确认已启动 apiserver.exe")
return None
if data.get("code") != 0:
print(f"❌ 环境启动失败: {data.get('message')}")
return None
ws = data["data"]["ws"]
print(f"✅ 环境已开启,ws 地址: {ws}")
return ws
def main():
ws_endpoint = get_ws_endpoint(SESSION_ID)
if not ws_endpoint:
return
with sync_playwright() as p:
# ── connectOverCDP 接管候鸟浏览器 ─────────────────
browser = p.chromium.connect_over_cdp(ws_endpoint)
print("🎉 Playwright 接管成功!")
# 取候鸟已有的默认 BrowserContext(保留所有 Cookie、存储等)
context = browser.contexts[0]
# 取第一个页面,如果没有则新建
page = context.pages[0] if context.pages else context.new_page()
# ── 执行业务操作 ───────────────────────────────────
page.goto("https://www.mbbrowser.com", wait_until="domcontentloaded")
print(f"📄 当前页面标题: {page.title()}")
page.wait_for_timeout(3000)
print("✅ 脚本执行完毕!")
browser.close()
if __name__ == "__main__":
main()运行(在候鸟虚拟环境中,或直接用系统 Python):
bash
python start_playwright.py方式三:Java 版本
NOTE
Java 版本建议通过候鸟客户端的自动化脚本管理器来运行,候鸟会自动处理 Playwright JAR 包和驱动提取。以下代码可以直接在脚本编辑器中使用。
java
import com.microsoft.playwright.*;
import java.net.URI;
import java.net.http.*;
import org.json.*;
public class MBPlaywright {
static final String API_URL = "http://127.0.0.1:8186";
static final String SESSION_ID = "替换为您的环境ID";
public static void main(String[] args) throws Exception {
// ── 第一步:调用 ApiServer 开启环境 ──────────────
System.out.println("⏳ 正在开启候鸟环境...");
HttpClient httpClient = HttpClient.newHttpClient();
String body = "{\"Session_ID\":\"" + SESSION_ID + "\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_URL + "/api/v1/browser/start"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString()
);
JSONObject data = new JSONObject(response.body());
String wsEndpoint = data.getJSONObject("data").getString("ws");
System.out.println("✅ 环境已开启,ws: " + wsEndpoint);
// ── 第二步:Playwright connectOverCDP 接管 ────────
// 设置跳过内置浏览器下载(用候鸟的)
System.setProperty("playwright.skip.browser.download", "1");
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().connectOverCDP(wsEndpoint);
System.out.println("🎉 Playwright 接管成功!");
BrowserContext context = browser.contexts().get(0);
Page page = context.pages().isEmpty()
? context.newPage()
: context.pages().get(0);
page.navigate("https://www.mbbrowser.com");
System.out.println("📄 当前页面标题: " + page.title());
Thread.sleep(3000);
System.out.println("✅ 脚本执行完毕!");
browser.close();
}
}
}关键代码解析
connectOverCDP vs launch ——最核心的区别
javascript
// ❌ 普通 Playwright 用法:新建一个空白的 Chrome 窗口
const browser = await chromium.launch();
// ✅ 候鸟 Playwright 用法:接管已有的指纹环境
const browser = await chromium.connectOverCDP(wsEndpoint);| 对比 | 普通 launch() | 候鸟 connectOverCDP() |
|---|---|---|
| 浏览器状态 | 全新空白,什么都没有 | 已有完整指纹、代理、Cookie |
| 执行后果 | 目标网站看到裸机 Chrome | 目标网站看到"真实用户" |
| 多账号管理 | 无法区分 | 按 Session_ID 精确对应 |
为什么取 data.ws 而不是 data.http?
| 字段 | 格式示例 | 适用框架 |
|---|---|---|
data.http | 127.0.0.1:9222 | Selenium(debuggerAddress) |
data.ws | ws://127.0.0.1:9222/devtools/browser/xxx | Playwright / Puppeteer ✅ |
Playwright 的 connectOverCDP 需要完整的 ws://... 地址。
browser.contexts()[0] ——不要创建新上下文
javascript
// ❌ 错误:创建全新上下文,候鸟的 Cookie 和存储会丢失
const context = await browser.newContext();
// ✅ 正确:取候鸟已有的上下文(保留所有账号状态)
const context = browser.contexts()[0];常见问题排查
❓ 报错 Error: connect ECONNREFUSED 127.0.0.1:8186
ApiServer 没有启动,或端口不对。请确认 apiserver.exe 的终端窗口还在运行。
❓ 报错 Browser closed 或 Target page, context or browser has been closed
候鸟环境已被关闭(可能超时或手动关闭),需要重新调用 /api/v1/browser/start 开启。
❓ browser.contexts() 返回空数组
候鸟环境刚打开时,默认 Context 可能需要短暂初始化,加个等待:
javascript
// 等待上下文出现(最多 5 秒)
let context;
for (let i = 0; i < 50 && !browser.contexts().length; i++) {
await new Promise(r => setTimeout(r, 100));
}
context = browser.contexts()[0];❓ browser.close() 关闭了候鸟窗口?
connectOverCDP 模式下,browser.close() 只断开 Playwright 的连接,不会关闭候鸟的浏览器窗口。若需关闭,调用候鸟 ApiServer 的 stop 接口:
javascript
await axios.post(`${API_URL}/api/v1/browser/stop`, { Session_ID: SESSION_ID });TIP
跑起来了?下一章 核心 API 通俗详解 教您用 Playwright 强大的 Locator、Page 等 API 完成各种页面操作。
