浏览器自动化技术全景:Playwright + Midscene.js 核心原理与实战方案

浏览器自动化技术全景:Playwright + Midscene.js 核心原理与实战方案

目录

  1. 核心技术原理
  • 1.1 Playwright 底层架构与通信机制

  • 1.2 Playwright 三大核心机制(稳 / 快关键)

  • 1.3 BrowserContext 隔离原理

  • 1.4 CDP 协议(Chrome DevTools Protocol)核心

  • 1.5 Midscene.js 纯视觉驱动原理

  • 1.6 WebSocket 为何成为 CDP 默认协议

  1. 实战技术方案
  • 2.1 Playwright 常用 API 速查表

  • 2.2 CDP 常用命令速查表

  • 2.3 Midscene.js 脚本生成与执行

  • 2.4 多账号 / 多会话隔离方案

  • 2.5 脚本速度优化方案

  • 2.6 脚本失败自动自愈方案

  • 2.7 验证码处理方案

  • 2.8 自然语言生成自动化脚本方案

  1. 常见问题与解决方案(FAQ)

一、核心技术原理

1.1 Playwright 底层架构与通信机制

Playwright 是微软开源的跨浏览器自动化工具,核心架构为「三层架构 + WebSocket 长连接」,实现高效、稳定的自动化控制。

架构图

┌─────────────────────────────────────────────────────────────┐

│                      你的业务代码                            │

│  (Python / JS / Java / C# 任意语言)                          │

└───────────────────────────┬─────────────────────────────────┘

                          │

                          ▼

┌─────────────────────────────────────────────────────────────┐

│                  Playwright Client SDK                       │

│  - 封装 API:click / fill / goto / locator 等                │

│  - 实现:自动等待、重试、可交互判断、超时管理                │

└───────────────────────────┬─────────────────────────────────┘

                          │

                           │ WebSocket 长连接(双向通信、事件推送)

                           ▼

┌─────────────────────────────────────────────────────────────┐

│                  Playwright Driver (Node.js 核心)            │

│  - 多语言桥接层                                              │

│  - 协议转换:统一封装成浏览器可识别的指令                    │

│  - 事件分发、日志、追踪、调试能力                            │

└───────────────────────────┬─────────────────────────────────┘

                           │

          ┌───────────────┴───────────────┬───────────────┐

          │                               │               │

          ▼                               ▼               ▼

┌──────────────────┐          ┌──────────────────┐ ┌──────────────────┐

│   Chromium       │          │     Firefox      │ │     WebKit       │

│  使用 CDP 协议    │          │  自研调试协议    │ │  自研调试协议    │

└────────┬─────────┘          └──────────────────┘ └──────────────────┘

        │

        │ Chrome DevTools Protocol (CDP) - WebSocket + JSON-RPC

        ▼

┌─────────────────────────────────────────────────────────────┐

│                    浏览器内核进程                            │

│   (Renderer / Network / DOM / V8 / Input 等子系统)          │

└─────────────────────────────────────────────────────────────┘

核心通信链路

你的代码 → Playwright SDK(自动等待)→ Driver(协议转换)→ 浏览器(CDP/自研协议)→ 内核执行

→ 浏览器主动推送事件 → Driver 分发 → SDK 接收 → 业务代码继续执行

1.2 Playwright 三大核心机制(稳 / 快关键)

1.2.1 自动等待(Auto-Wait)

  • 实现原理:客户端判断 + 轻量状态获取 + 智能重试(非轮询)
  1. 调用 click/fill 等操作时,SDK 通过 CDP 向浏览器查询元素完整状态(是否存在、可见、可交互、无遮挡、无动画);

  2. 判断逻辑在客户端执行,不满足则极短间隔(几十 ms)再次查询;

  3. 满足条件立即执行,超时抛出可解读错误。

  • 核心价值:无需手动写 sleep/wait,稳定性大幅提升。

1.2.2 事件驱动

  • 实现原理:WebSocket 长连接 + 浏览器主动推送事件
  1. Playwright 启动时与浏览器建立持久 WebSocket 连接;

  2. 客户端提前订阅事件(DOM 变化、网络请求、页面加载完成等);

  3. 浏览器事件发生时主动推送至客户端,触发回调 / 继续执行。

  • 核心价值:无轮询开销,速度比 Selenium(HTTP 短连接 + 轮询)快 3~10 倍。

1.2.3 隔离上下文(BrowserContext)

  • 实现原理:浏览器原生多分区存储 + 上下文 ID 隔离
  1. 一个 Browser 进程可创建多个 BrowserContext,每个 Context 对应独立的 StoragePartition

  2. 独立资源包括:Cookie Jar、LocalStorage/SessionStorage、缓存分区、代理、权限、UA;

  3. 底层依赖浏览器原生能力(Chromium 用 BrowserContextID + StoragePartition,Firefox/WebKit 由 Playwright 做兼容层)。

  • 核心价值:测试用例互不干扰,支持多账号、多场景并行。

1.3 BrowserContext 隔离原理与共享机制

隔离核心

  • 本质:每个 BrowserContext 是独立的「浏览器账号分身」,数据物理隔离(跨 Context 无数据泄漏);

  • 层级关系:Browser → N 个 Context → 每个 Context 下 N 个 Page(Tab)

  • Page 永远属于创建它的 Context,无法跨 Context 迁移。

数据共享方案(显式导出 / 导入)

  1. 共享 Cookie
const cookies = await context1.cookies(); // 导出

await context2.addCookies(cookies); // 导入
  1. 共享 LocalStorage/SessionStorage
// 导出

const localStorage = await page1.evaluate(() => JSON.stringify(localStorage));

// 导入

await page2.evaluate((data) => {

 const ls = JSON.parse(data);

 for (const k in ls) localStorage.setItem(k, ls\[k]);

}, localStorage);
  1. 共享用户数据目录(profile)
// 两个浏览器实例共享同一 profile(注意:不可多进程同时写)

const browser1 = await chromium.launch({ userDataDir: './my-profile' });

const browser2 = await chromium.launch({ userDataDir: './my-profile' });
  1. 共享网络配置(代理、权限等):创建 Context 时传入相同配置。

1.4 CDP 协议(Chrome DevTools Protocol)核心

什么是 CDP?

  • Chromium 官方提供的底层调试 / 控制协议,Chrome DevTools(F12)的核心通信协议;

  • 基于 WebSocket + JSON-RPC,双向通信,按「域(Domain)」组织能力。

Playwright 与 CDP 的关系

  • Chromium 场景:Playwright 所有高层 API(如 click/fill)最终都转为 CDP 命令执行;

  • Firefox/WebKit 场景:Playwright 提供兼容层,行为与 CDP 一致;

  • 支持直接调用原生 CDP 命令(高级用法):

const cdp = await page.context().newCDPSession(page);

await cdp.send("Network.enable"); // 启用网络域

cdp.on("Network.requestWillBeSent", (e) => console.log("请求URL:", e.request.url));

CDP 常用域与命令

核心能力 示例命令
Page 页面控制 Page.navigatePage.captureScreenshot
Network 网络拦截 / 监控 Network.enableNetwork.setRequestInterception
Runtime JS 执行 Runtime.evaluateRuntime.callFunctionOn
DOM DOM 操作 DOM.querySelectorDOM.getBoxModel
Input 模拟输入 / 点击 Input.dispatchMouseEventInput.insertText
Emulation 设备 / UA 模拟 Emulation.setDeviceMetricsOverride
Performance 性能监控 Performance.getMetrics

1.5 Midscene.js 纯视觉驱动原理

核心定位:纯视觉(截图)驱动

  • 不依赖 XPath/CSS 选择器,通过「截图 + 视觉大模型(VLM)」识别元素、返回坐标,映射为操作;

  • DOM 仅用于数据提取,UI 操作完全基于视觉。

工作流程

  1. 设备层(Playwright/Puppeteer/ADB 等)捕获页面 / 屏幕截图(Base64 格式);

  2. 截图预处理(压缩、隐藏鼠标、简化上下文),减少 Token 消耗;

  3. 截图 + 指令传给 VLM(如 Qwen3-VL、Doubao-vision),返回目标元素坐标;

  4. 坐标映射为设备可执行动作(click/tap/fill)。

脚本生成方式

  1. 自然语言(自动规划)
await aiAct('打开淘宝,搜索“手机”,点击第一个商品,提取价格');
  1. JavaScript SDK(工作流风格)
const agent = new Midscene(page);

await agent.aiTap('登录按钮');

await agent.aiInput('用户名输入框', 'test@example.com');

const price = await agent.aiQuery('提取商品价格');
  1. YAML 配置(低代码)
web: { url: https://example.com }

tasks:

 - name: 登录流程

   flow:

     - ai: 点击登录按钮

     - aiInput: \[用户名输入框, test@example.com]

     - aiAssert: 页面显示“欢迎回来”
  1. 零代码生成:Chrome 插件(桥接模式)、Web/Android/iOS Playground 可视化操作生成脚本。

1.6 WebSocket 为何成为 CDP 默认协议

核心原因

WebSocket 是浏览器唯一能满足 CDP 需求的协议:全双工 + 长连接 + 低延迟 + 事件推送

核心优势

  1. 全双工通信:客户端与浏览器可同时收发数据,无需等待请求 - 响应;

  2. 长连接:一次握手后持续通信,无 TCP 握手和 HTTP 头冗余开销;

  3. 浏览器主动推送事件:CDP 需浏览器实时推送 DOM 变化、网络请求等事件,WebSocket 是唯一支持该能力的浏览器原生协议;

  4. 轻量高效:帧头仅 2~10 字节,远小于 HTTP 头(几百~几千字节);

  5. 跨语言 / 跨平台:所有主流语言(JS/Python/Java 等)均支持,无平台差异。

为何不选择其他协议?

  • HTTP:半双工、短连接,服务器无法主动推送,只能轮询(慢、耗资源);

  • TCP 原生:浏览器不暴露原生 TCP 接口,无跨平台标准,不安全;

  • gRPC/QUIC/WebRTC:gRPC 太重、QUIC 生态不成熟、WebRTC 适用于音视频,均不适合调试协议场景。


二、实战技术方案

2.1 Playwright 常用 API 速查表

1. 启动与基础配置

// 启动浏览器

const browser = await chromium.launch({ headless: false, args: \['--no-sandbox'] });

// 新建隔离上下文

const context = await browser.newContext({

 userAgent: 'Mozilla/5.0...',

 viewport: { width: 1280, height: 800 },

 proxy: { server: 'http://127.0.0.1:8888' }

});

// 新建页面

const page = await context.newPage();

await page.goto('https://www.baidu.com'); // 访问页面

2. 元素操作(自动等待)

await page.click('selector'); // 点击

await page.fill('selector', '文本'); // 输入(清空后填充)

await page.type('selector', '文本'); // 模拟打字输入

await page.press('selector', 'Enter'); // 按键

await page.selectOption('selector', 'value'); // 下拉选择

await page.check('selector'); // 勾选复选框

await page.hover('selector'); // 悬停

3. 等待与断言

await page.waitForSelector('selector'); // 等待元素出现

await page.waitForLoadState('networkidle'); // 等待网络空闲

await page.waitForURL('\*\*/result'); // 等待URL匹配

await page.isVisible('selector'); // 判断元素可见

await page.isEnabled('selector'); // 判断元素可用

4. 数据提取

await page.title(); // 获取页面标题

await page.url(); // 获取当前URL

await page.textContent('selector'); // 获取文本内容

await page.getAttribute('selector', 'href'); // 获取属性

await page.inputValue('selector'); // 获取输入框值

5. 网络拦截与模拟

// 拦截请求并修改响应

await page.route('\*\*/api/\*', async (route) => {

 await route.fulfill({ body: JSON.stringify({ code: 200 }) });

 // await route.abort(); // 中止请求

 // await route.continue(); // 继续请求

});

6. 多页面 / 弹窗处理

// 监听新页面(如点击新标签页链接)

const \[newPage] = await Promise.all(\[

 context.waitForEvent('page'),

 page.click('a\[target="\_blank"]')

]);

// 处理弹窗(alert/confirm)

page.on('dialog', async (dialog) => await dialog.accept());

7. 截图与导出

await page.screenshot({ path: 'result.png', fullPage: true }); // 全屏截图

await page.pdf({ path: 'page.pdf', format: 'A4' }); // 导出PDF

2.2 CDP 常用命令速查表

1. 页面控制(Page 域)

await cdp.send('Page.navigate', { url: 'https://example.com' }); // 跳转页面

await cdp.send('Page.reload'); // 刷新页面

const screenshot = await cdp.send('Page.captureScreenshot'); // 截图(Base64)

await cdp.send('Page.setViewport', { viewport: { width: 1280, height: 800 } }); // 设置视口

2. 网络控制(Network 域)

await cdp.send('Network.enable'); // 启用网络监听

await cdp.send('Network.setRequestInterception', { patterns: \[{ urlPattern: '\*\*/api/\*' }] }); // 拦截请求

const cookies = await cdp.send('Network.getCookies'); // 获取Cookie

await cdp.send('Network.setCookies', { cookies: \[{ name: 'key', value: 'val', domain: 'example.com' }] }); // 设置Cookie

3. JS 执行(Runtime 域)

const result = await cdp.send('Runtime.evaluate', { expression: 'document.title' }); // 执行JS

console.log('页面标题:', result.result.value);

4. DOM 操作(DOM 域)

const root = await cdp.send('DOM.getDocument'); // 获取文档根节点

const element = await cdp.send('DOM.querySelector', { nodeId: root.root.nodeId, selector: '#login-btn' }); // 查找元素

const boxModel = await cdp.send('DOM.getBoxModel', { nodeId: element.nodeId }); // 获取元素位置/宽高

5. 输入模拟(Input 域)

// 模拟点击(坐标x=100, y=200)

await cdp.send('Input.dispatchMouseEvent', {

 type: 'click',

 x: 100,

 y: 200,

 button: 'left'

});

// 模拟输入文本

await cdp.send('Input.insertText', { text: 'test' });

6. 设备模拟(Emulation 域)

// 模拟手机设备

await cdp.send('Emulation.setDeviceMetricsOverride', {

 width: 375,

 height: 667,

 deviceScaleFactor: 2,

 mobile: true

});

// 修改UA

await cdp.send('Emulation.setUserAgentOverride', { userAgent: 'Mozilla/5.0...' });

2.3 Midscene.js 脚本生成与执行

核心 API 示例

const { Midscene } = require('@midscene/core');

const { chromium } = require('playwright');

(async () => {

 const browser = await chromium.launch({ headless: false });

 const page = await browser.newPage();

 const agent = new Midscene(page, { cache: true }); // 启用缓存提速

 // 1. 自然语言自动规划

 await agent.aiAct('打开百度,搜索“Playwright”,点击第一条结果');

 // 2. 即时操作(跳过规划,更快)

 await agent.aiTap('登录按钮', { deepThink: false }); // 关闭深度思考提速

 await agent.aiInput('用户名输入框', 'test@example.com');

 await agent.aiInput('密码框', '123456');

 await agent.aiTap('提交按钮');

 // 3. 数据提取与断言

 const price = await agent.aiQuery('提取商品价格,返回数字');

 await agent.aiAssert('页面包含“登录成功”');

 await browser.close();

})();

零代码脚本生成(Chrome 插件)

  1. 安装 Midscene Chrome 插件;

  2. 开启桥接模式,在浏览器中手动操作目标流程;

  3. 插件自动记录操作、截图、生成 JS/YAML 脚本;

  4. 导出脚本直接用于自动化执行。

2.4 多账号 / 多会话隔离方案

Playwright 最优实现(单浏览器多 Context)

const { chromium } = require('playwright');

(async () => {

 const browser = await chromium.launch({ headless: false });

 // 账号1:上下文1(独立Cookie/存储)

 const ctx1 = await browser.newContext();

 const page1 = await ctx1.newPage();

 await page1.goto('https://example.com/login');

 await page1.fill('#username', 'user1');

 await page1.fill('#password', 'pass1');

 await page1.click('#login');

 // 账号2:上下文2(完全隔离)

 const ctx2 = await browser.newContext();

 const page2 = await ctx2.newPage();

 await page2.goto('https://example.com/login');

 await page2.fill('#username', 'user2');

 await page2.fill('#password', 'pass2');

 await page2.click('#login');

 // 并行操作,互不干扰

 await Promise.all(\[

   page1.goto('https://example.com/account'),

   page2.goto('https://example.com/account')

 ]);

 await browser.close();

})();

优势对比 Selenium

  • Selenium 需启动多个浏览器实例(内存占用高、速度慢);

  • Playwright 单浏览器多 Context(内存低、速度快、隔离彻底)。

2.5 脚本速度优化方案

Midscene.js 提速 10 倍方案

  1. 优先使用即时操作:替代 aiAct,跳过 AI 规划;
// 慢:自动规划

await agent.aiAct('点击登录按钮');

// 快:即时操作

await agent.aiTap('登录按钮');
  1. 关闭深度思考:简单场景禁用 deepThink
await agent.aiTap('登录按钮', { deepThink: false });
  1. 启用缓存:缓存截图 / 模型结果,避免重复推理;
const agent = new Midscene(page, { cache: true });
  1. 压缩截图 + 减少上下文:降低截图质量(JPEG 70-80),关闭 DOM 附加;

  2. 无头模式 + 浏览器优化

const browser = await chromium.launch({

 headless: true,

 args: \['--disable-gpu', '--no-sandbox', '--disable-extensions']

});
  1. 选择轻量 VLM 模型:优先 Qwen3-VL-8B/Doubao-1.6-vision-tiny

  2. 并行执行:用 Promise.all 并行处理独立操作;

  3. 合并 AI 调用:一次 aiQuery 提取多个数据,减少模型调用次数。

Playwright 提速方案

  1. 禁用不必要的浏览器功能(如 GPU、扩展);

  2. 使用 BrowserContext 复用浏览器进程,避免重复启动;

  3. 网络拦截 mock 静态资源,减少加载时间;

  4. 避免 waitForTimeout,使用 waitForSelector/waitForLoadState

2.6 脚本失败自动自愈方案

核心原理

传统定位(CSS/XPath)失败 → 自动触发 AI 视觉定位 → 修复并更新缓存,实现 “页面变动不崩”。

工业级实现代码(Midscene 风格)

class AutoHealAgent {

 constructor(page, vlmService) {

   this.page = page;

   this.vlmService = vlmService;

   this.cache = new Map(); // 缓存:元素描述 → 选择器/坐标

 }

 // 检查元素是否存在

 async exists(selector) {

   try {

     return await this.page.locator(selector).isVisible({ timeout: 1000 });

   } catch (e) {

     return false;

   }

 }

 // 自动自愈的点击方法

 async aiTap(desc) {

   // 1. 优先使用缓存的选择器(快速路径)

   const cachedSelector = this.cache.get(desc);

   if (cachedSelector && await this.exists(cachedSelector)) {

     await this.page.click(cachedSelector);

     return;

   }

   // 2. 尝试生成传统选择器(基于描述)

   const possibleSelectors = this.generateSelectors(desc);

   for (const selector of possibleSelectors) {

     if (await this.exists(selector)) {

       await this.page.click(selector);

       this.cache.set(desc, selector); // 更新缓存

       return;

     }

   }

   // 3. 传统定位失败 → 调用 AI 视觉定位(自愈)

   const screenshot = await this.page.screenshot();

   const aiResult = await this.vlmService.locate(screenshot, desc);

   if (aiResult.found) {

     const { x, y } = aiResult;

     await this.page.mouse.click(x, y); // 坐标点击

     // 缓存最佳选择器(供下次快速使用)

     this.cache.set(desc, aiResult.bestSelector || \`\[data-ai-loc="\${desc}"]\`);

     return;

   }

   throw new Error(\`未找到元素:\${desc}\`);

 }

 // 基于描述生成可能的选择器

 generateSelectors(desc) {

   const text = desc.replace(/按钮|输入框|链接/, '');

   return \[

     \`button:contains("\${text}")\`,

     \`input\[placeholder\*="\${text}"]\`,

     \`a:contains("\${text}")\`,

     \`#\${text.toLowerCase()}-btn\`,

     \`.\${text.toLowerCase()}-btn\`

   ];

 }

}

// 使用示例

const agent = new AutoHealAgent(page, vlmService);

await agent.aiTap('登录按钮'); // 自动自愈,页面变动也能执行

2.7 验证码处理方案

工业级组合方案(Midscene + 验证码服务)

const { Midscene } = require('@midscene/core');

const ddddocr = require('ddddocr'); // 免费本地OCR

const CaptchaCloudService = require('./captcha-cloud'); // 云打码兜底

(async () => {

 const browser = await chromium.launch({ headless: false });

 const page = await browser.newPage();

 const agent = new Midscene(page);

 const ocr = new ddddocr.DdddOcr();

 const cloudCaptcha = new CaptchaCloudService({ apiKey: 'your-key' });

 // 1. 触发登录,等待验证码出现

 await agent.aiTap('登录按钮');

 await agent.aiWait('验证码图片');

 // 2. 截取验证码区域

 const captchaLocator = page.locator('img\[alt\*="验证码"]');

 const captchaBuffer = await captchaLocator.screenshot();

 // 3. 验证码识别(本地OCR优先,云打码兜底)

 let code;

 try {

   // 本地OCR识别字符验证码/滑块缺口

   code = ocr.classify(captchaBuffer);

 } catch (e) {

   // 本地失败 → 云打码(支持复杂验证码)

   code = await cloudCaptcha.recognize(captchaBuffer);

 }

 // 4. 输入验证码并提交

 await agent.aiInput('验证码输入框', code);

 await agent.aiTap('提交按钮');

 // 5. 失败重试(验证码错误时)

 if (await page.isVisible('text=验证码错误')) {

   // 重新识别并输入

   const newCaptchaBuffer = await captchaLocator.screenshot();

   code = await cloudCaptcha.recognize(newCaptchaBuffer);

   await agent.aiInput('验证码输入框', code, { force: true }); // 强制覆盖

   await agent.aiTap('提交按钮');

 }

 await browser.close();

})();

主流验证码解决方案对比

方案 适用场景 速度 成本 成功率
ddddocr(本地 OCR) 字符、滑块验证码 免费 95%+
云打码(超级鹰等) 复杂点选、行为验证码 收费 99%+
VLM 大模型(GPT-4V) 全类型验证码 98%+
Playwright + stealth 风控类无感验证码 免费 90%+

2.8 自然语言生成自动化脚本方案

最佳架构:自然语言 → Playwright 脚本 + AI 自愈兜底

  1. 自然语言输入:用户描述任务(如 “打开淘宝,搜索 iPhone,提取前 5 个商品价格”);

  2. 大模型生成脚本:LLM(GPT/Qwen/Doubao)拆解意图,生成 Playwright 脚本;

  3. 运行时自愈:脚本执行时选择器失效,自动触发 AI 视觉定位兜底。

生成示例(自然语言 → Playwright 脚本)

自然语言指令:打开百度,输入 “Playwright 教程”,点击搜索,等待结果加载,截图保存为 result.png

生成的 Playwright 脚本

const { chromium } = require('playwright');

(async () => {

 // 启动浏览器

 const browser = await chromium.launch({ headless: false });

 const context = await browser.newContext();

 const page = await context.newPage();

 // 访问百度

 await page.goto('https://www.baidu.com');

 // 输入搜索关键词

 await page.fill('#kw', 'Playwright 教程');

 // 点击搜索按钮

 await page.click('#su');

 // 等待结果加载

 await page.waitForSelector('#content\_left', { timeout: 5000 });

 // 截图保存

 await page.screenshot({ path: 'result.png', fullPage: true });

 // 关闭浏览器

 await browser.close();

})();

落地工具推荐

  • 代码生成:GPT-4、Qwen-Code、Doubao-Code;

  • 脚本执行:Playwright + Midscene 自愈引擎;

  • 零代码工具:Midscene Playground、Chrome 插件。


三、常见问题与解决方案(FAQ)

1. Playwright 相关

Q1:Playwright 如何实现多账号隔离?

A1:通过 BrowserContext 实现,每个 Context 对应独立的存储分区(Cookie、LocalStorage、缓存等),单浏览器可创建多个 Context,实现多账号并行且隔离。

Q2:如何找到 Playwright 中对应的 Tab 页 / Context?

A2:

  • 层级关系:Browser → Context → Page(Tab)

  • 从 Page 反查 Context:page.context()

  • 从 Context 获取所有 Page:context.pages()

  • 监听新 Page:context.on('page', (newPage) => { ... })

  • 无需切换 Tab,直接操作 Page 对象。

Q3:Playwright 比 Selenium 快的核心原因是什么?

A3:

  • 通信协议:Playwright 用 WebSocket 长连接 + 事件推送,Selenium 用 HTTP 短连接 + 轮询;

  • 自动等待:Playwright 内置元素可交互判断,Selenium 需手动写等待;

  • 架构优化:Playwright 直接控制浏览器内核,Selenium 依赖 WebDriver 中间层。

Q4:Playwright 如何共享不同 Context 的数据?

A4:显式导出 / 导入:

  • Cookie:context1.cookies() 导出 → context2.addCookies() 导入;

  • LocalStorage:通过 page.evaluate() 序列化导出后导入;

  • 共享用户数据目录:启动浏览器时指定 userDataDir

2. Midscene.js 相关

Q1:Midscene.js 是基于截图的吗?

A1:是,核心是纯视觉驱动,UI 操作(点击 / 输入)完全基于截图 + VLM 识别,DOM 仅用于数据提取。

Q2:Midscene 生成脚本后,下次运行还要调用 AI 吗?

A2:默认需要,但可通过缓存 + 传统定位降级优化:

  • 第一次运行:AI 识别 → 缓存元素位置 / 选择器;

  • 后续运行:优先使用缓存 / 传统选择器,失败再调用 AI,速度提升 10~50 倍。

Q3:Midscene 脚本失败(页面变动)如何自动修复?

A3:自动自愈机制:

  1. 传统定位失败 → 自动截图;

  2. 调用 VLM 重新识别元素;

  3. 执行操作并更新缓存;

  4. 下次直接使用新缓存,无需重复 AI 调用。

Q4:Midscene 如何与验证码结合?

A4:

  1. 触发登录后,等待验证码出现并截图;

  2. 调用验证码服务(ddddocr 本地 OCR / 云打码 / VLM)识别;

  3. 输入验证码并提交;

  4. 验证码错误时自动重试。

3. CDP 与协议相关

Q1:CDP 为什么默认使用 WebSocket 协议?

A1:WebSocket 是唯一满足 CDP 需求的协议:

  • 全双工通信:客户端与浏览器可同时收发数据;

  • 长连接:无频繁握手开销;

  • 浏览器主动推送事件:支持 DOM 变化、网络请求等实时通知;

  • 轻量高效:帧头开销小,跨语言 / 跨平台支持好。

Q2:Playwright 如何直接调用 CDP 命令?

A2:通过 CDPSession 建立会话,示例:

const cdp = await page.context().newCDPSession(page);

await cdp.send('Network.enable'); // 启用网络域

cdp.on('Network.requestWillBeSent', (e) => console.log('请求URL:', e.request.url));

4. 工具选型相关

Q1:为什么现在自动化插件都基于 Playwright 而非 Selenium/Puppeteer?

A1:

  • 对比 Selenium:Playwright 更快(WebSocket 长连接)、更稳(自动等待)、支持多上下文隔离;

  • 对比 Puppeteer:Playwright 跨浏览器(Chrome/Firefox/WebKit)、跨语言(JS/Python/Java 等)、生态更完善;

  • 原生支持 CDP,架构现代,迭代速度快(微软维护)。

Q2:Midscene.js 与 Playwright 该如何选择?

A2:

  • 选 Playwright:专业开发者、稳定页面、追求极致速度、需要精准控制;

  • 选 Midscene.js:非开发者、频繁变动的页面、零代码 / 低代码场景、需要自然语言操作。

Q3:验证码处理有哪些推荐方案?

A3:

  • 免费方案:ddddocr(本地 OCR,支持字符 / 滑块验证码);

  • 稳定方案:云打码(超级鹰 / 图鉴,支持复杂点选 / 行为验证码);

  • 通用方案:VLM 大模型(GPT-4V/Qwen-VL,全类型验证码);

  • 风控方案:Playwright + stealth 插件(去除自动化特征)。

posted @ 2026-03-09 15:47  愤怒的企鹅  阅读(17)  评论(0)    收藏  举报