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 }; }