import type { Browser, LaunchOptions } from "playwright"; export type BrowserLaunchOptions = { headless: boolean; slowMo?: number; /** Chrome 无痕窗口,每次启动无 cookie 残留 */ incognito?: boolean; }; function readBrowserChannel(): "chrome" | "msedge" | undefined { const raw = process.env.RPA_BROWSER_CHANNEL?.trim().toLowerCase(); if (raw === "chrome" || raw === "msedge") { return raw; } return undefined; } function buildLaunchOptions(opts: BrowserLaunchOptions): LaunchOptions { const channel = readBrowserChannel(); return { headless: opts.headless, ...(opts.slowMo !== undefined ? { slowMo: opts.slowMo } : {}), ...(channel ? { channel } : {}), args: [ "--disable-blink-features=AutomationControlled", "--disable-dev-shm-usage", "--disable-features=TranslateUI", ...(opts.incognito ? ["--incognito"] : []), ], }; } /** 启动浏览器:stealth > patchright > playwright,可选本地 Chrome channel */ export async function launchRpaBrowser( opts: BrowserLaunchOptions, ): Promise { const launchOpts = buildLaunchOptions(opts); if (process.env.RPA_USE_STEALTH === "true") { try { const { chromium } = await import("playwright-extra"); const StealthPlugin = (await import("puppeteer-extra-plugin-stealth")) .default; chromium.use(StealthPlugin()); return chromium.launch(launchOpts); } catch (error) { console.warn( "[browser-launch] stealth 未安装或启动失败,回退默认 chromium", error instanceof Error ? error.message : error, ); } } if (process.env.RPA_USE_PATCHRIGHT === "true") { try { const patchright = (await import( /* webpackIgnore: true */ "patchright" as string )) as { chromium: { launch: (o: LaunchOptions) => Promise }; }; return patchright.chromium.launch(launchOpts); } catch { console.warn("[browser-launch] patchright 未安装,回退 playwright"); } } const { chromium } = await import("playwright"); return chromium.launch(launchOpts); }