79 lines
3.5 KiB
JavaScript
79 lines
3.5 KiB
JavaScript
import { chromium } from 'playwright';
|
||
import fetch from 'node-fetch';
|
||
|
||
// 连接指纹浏览器优先级:
|
||
// 1) AdsPower 本地 API(设置 ADSPOWER_USER_ID)
|
||
// 2) 自定义 WS 端点(设置 BROWSER_WS_ENDPOINT)
|
||
// 3) 本地 Playwright 启动(默认)
|
||
|
||
export async function getBrowserAndContexts({ headless, slowMo }) {
|
||
// 尝试 AdsPower
|
||
const adspowerUserId = process.env.ADSPOWER_USER_ID;
|
||
if (adspowerUserId) {
|
||
console.log('[FP] 使用 AdsPower 指纹浏览器');
|
||
const apiBase = process.env.ADSPOWER_API || 'http://local.adspower.net:50325';
|
||
const apiKey = process.env.ADSPOWER_API_KEY;
|
||
let startUrl = `${apiBase}/api/v1/browser/start?user_id=${encodeURIComponent(adspowerUserId)}`;
|
||
if (apiKey && apiKey.trim()) {
|
||
startUrl += `&api_key=${encodeURIComponent(apiKey)}`;
|
||
console.log('[FP] 使用 API Key 认证');
|
||
}
|
||
const resp = await fetch(startUrl);
|
||
const data = await resp.json();
|
||
if (data.code !== 0) {
|
||
console.error('[AdsPower] API 返回错误:', JSON.stringify(data, null, 2));
|
||
console.error('\n解决方案:');
|
||
console.error('1. 确保 AdsPower 应用已启动并登录');
|
||
console.error('2. 检查配置文件 ID 是否正确: ' + adspowerUserId);
|
||
console.error('3. 如果需要 API Key,请在 AdsPower 设置中生成并设置环境变量 ADSPOWER_API_KEY');
|
||
console.error('4. 尝试在 AdsPower 中手动打开一次浏览器配置文件\n');
|
||
throw new Error(`[AdsPower] 启动失败: ${data.msg || JSON.stringify(data)}`);
|
||
}
|
||
const wsEndpoint = data.data.ws && (data.data.ws.puppeteer || data.data.ws.selenium || data.data.ws.ws || data.data.ws);
|
||
console.log('[FP] AdsPower ws:', wsEndpoint);
|
||
const browser = await chromium.connectOverCDP(wsEndpoint);
|
||
const contexts = browser.contexts();
|
||
const baseContext = contexts[0] || await browser.newContext();
|
||
// AdsPower 需要至少保留一个标签页,关闭多余的
|
||
const existingPages = baseContext.pages();
|
||
if (existingPages.length > 1) {
|
||
for (let i = 1; i < existingPages.length; i++) {
|
||
try { await existingPages[i].close(); } catch {}
|
||
}
|
||
}
|
||
// 在同一个指纹环境下创建两个页签(同上下文不同页)
|
||
return {
|
||
browser,
|
||
emailContext: baseContext,
|
||
registerContext: baseContext,
|
||
};
|
||
}
|
||
|
||
// 尝试自定义 WS 端点
|
||
const ws = process.env.BROWSER_WS_ENDPOINT;
|
||
if (ws) {
|
||
console.log('[FP] 连接到自定义指纹浏览器 WS');
|
||
const browser = await chromium.connectOverCDP(ws);
|
||
const contexts = browser.contexts();
|
||
const baseContext = contexts[0] || await browser.newContext();
|
||
for (const p of baseContext.pages()) { try { await p.close(); } catch {} }
|
||
return {
|
||
browser,
|
||
emailContext: baseContext,
|
||
registerContext: baseContext,
|
||
};
|
||
}
|
||
|
||
// 回退:Playwright 本地启动
|
||
console.log('[FP] 未检测到指纹浏览器,使用内置 Chromium');
|
||
const browser = await chromium.launch({ headless, slowMo, args: ['--disable-blink-features=AutomationControlled', '--no-sandbox'] });
|
||
const emailContext = await browser.newContext({ viewport: { width: 1280, height: 720 } });
|
||
const registerContext = await browser.newContext({ viewport: { width: 1280, height: 720 } });
|
||
// 清理所有初始页面,保持上下文干净
|
||
for (const ctx of [emailContext, registerContext]) {
|
||
const pages = ctx.pages();
|
||
for (const p of pages) { try { await p.close(); } catch {} }
|
||
}
|
||
return { browser, emailContext, registerContext };
|
||
}
|