返回文章列表
1531 字 · 6 分钟

Playwright 接管本地 Edge:复用登录态操作真实网页

· 编辑文章

前两天折腾了一个挺有意思的事情。

不是让 Playwright 自己启动一个全新的浏览器,而是直接连接到我本地已经打开、已经登录的 Edge 浏览器,然后继续操作里面的网页。

这个需求其实非常真实。

很多时候我们并不是在做自动化测试,而是在处理一些日常工作:

  • 使用已经登录的论坛账号发帖、回复
  • 打开真实页面后让脚本继续操作
  • 避免重新登录和验证码
  • 在当前浏览器环境中完成自动化任务

这次我最终跑通了整个流程:

Playwright → 连接本地 Edge → 复用登录态 → 打开 NodeLoc → 进入帖子 → 自动发表评论。

Image

过程中踩了几个坑,顺手记录一下。


为什么不用 Playwright 自己启动浏览器?

平时大家写 Playwright,大多都是这样开始:

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

const browser = await chromium.launch();

这样当然没问题。

但有一个明显缺点:

这是一个全新的浏览器环境。

意味着:

  • 没有登录状态
  • 没有 Cookie
  • 没有 LocalStorage
  • 没有当前正在使用的网页

如果只是自动化测试,这很合适。

但如果你想操作一个真实网站、真实账号、真实页面,就会比较麻烦。

例如:

  • 论坛发帖
  • 后台管理系统
  • 工单系统
  • 社区运营页面

往往都需要重新登录。

而我的浏览器里其实早就已经登录好了。

既然如此,为什么不直接让 Playwright 接管当前浏览器呢?

于是思路就变成了:

浏览器开启远程调试
        ↓
获取 CDP 地址
        ↓
Playwright 连接已有浏览器
        ↓
复用登录态继续操作

第一个坑:PowerShell 启动命令报错

一开始我是这样启动 Chrome 的:

"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222

结果直接报错。

后来才反应过来:

这是 PowerShell,不是 CMD。

PowerShell 中执行带路径的程序,需要使用调用运算符:

&

正确写法:

& "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222

如果是 Edge:

& "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --remote-debugging-port=9222

虽然是个小坑,但第一次碰到确实容易卡住。


第二个坑:9222 端口打不开

启动后访问:

http://127.0.0.1:9222/json/version

结果提示:

127.0.0.1 拒绝了连接请求

最开始我还怀疑:

  • 防火墙
  • 浏览器版本
  • 系统代理

后来发现问题其实更简单:

浏览器原本就在后台运行。

新的启动参数根本没有生效。

也就是说:

你以为启动了一个带远程调试端口的浏览器。

实际上系统只是复用了原来的浏览器进程。


解决办法

方案一:关闭所有浏览器进程

彻底退出 Chrome 或 Edge 后重新启动。


方案二:单独创建调试配置

我后来更推荐这种方式:

& "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" `
  --remote-debugging-port=9222 `
  --user-data-dir="$env:TEMP\edge-cdp"

这样会启动一个独立的浏览器配置目录。

成功率更高。


获取 CDP 地址

远程调试启动成功后,访问:

http://127.0.0.1:9222/json/version

会返回类似:

{
  "webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/browser/xxxxxxxx"
}

其中最重要的就是:

webSocketDebuggerUrl

Playwright 连接本地浏览器

代码非常简单:

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

async function main() {
  const browser = await chromium.connectOverCDP(
    'ws://127.0.0.1:9222/devtools/browser/xxxx'
  );

  const context = browser.contexts()[0];

  const page = await context.newPage();

  await page.goto('https://www.nodeloc.com/', {
    waitUntil: 'domcontentloaded',
    timeout: 60000,
  });

  console.log(await page.title());

  await browser.close();
}

main();

实际上也可以直接写:

const browser = await chromium.connectOverCDP(
  'http://127.0.0.1:9222'
);

Playwright 会自动获取 WebSocket 地址。


真正让我觉得成功的瞬间

代码跑完并不稀奇。

真正让我觉得这事成了,是看到网页打开之后:

登录状态还在。

论坛账号还是登录状态。

Cookie 还在。

LocalStorage 也还在。

这时候的感觉完全不一样。

因为:

它已经不是在模拟一个新的浏览器访问网站。

而是在接管我正在使用的浏览器会话。


复用登录态到底有多省事?

如果使用传统 Playwright:

启动浏览器
↓
打开登录页
↓
输入账号密码
↓
处理验证码
↓
保持会话
↓
执行任务

而接管本地浏览器以后:

连接浏览器
↓
直接开始操作

中间所有登录相关步骤全部省掉。


我这次实际完成了什么?

整个流程如下:

连接本地 Edge
↓
复用论坛登录状态
↓
打开目标帖子
↓
定位回复框
↓
输入评论内容
↓
点击发送
↓
回复成功

提交完成后页面 URL 发生变化。

说明回复确实已经提交到真实网站。

不是模拟成功。

是真成功。


这种方案适合哪些场景?

1. 已登录网站操作

例如:

  • 论坛
  • 管理后台
  • CRM
  • 工单系统

最怕重新登录。

这种方式特别适合。


2. 半自动化流程

例如:

人工登录
↓
人工过验证码
↓
脚本接管
↓
自动执行后续任务

这是现实中最常见的场景。


3. 运营类工作

例如:

  • 发帖
  • 回复
  • 页面整理
  • 内容收集
  • 批量操作

都很方便。


4. 真实环境调试

有些问题:

新浏览器复现不了
真实浏览器能复现

这时候 CDP 接管会非常好用。


几个必须注意的问题

1. 不要暴露调试端口

远程调试权限非常高。

能连接的人基本就能控制你的浏览器。

因此建议:

只监听本机
不要映射公网
不要随便共享地址

2. 真实环境意味着真实后果

这不是测试环境。

你点点赞按钮:

真的会点赞。

你发评论:

真的会发出去。

因此最好先检查状态:

await expect(
  page.getByRole('button', { name: '发送' })
).toBeVisible();

确认无误再执行点击。


3. 不要把密码写进脚本

既然已经能复用登录态:

就没必要再保存账号密码。

安全性反而更高。


4. 优先使用语义化定位

相比这种:

#root > div > div:nth-child(3) > button

我更推荐:

getByRole()
getByText()
getByLabel()

代码更稳定。

页面改版也更不容易失效。


一点感受

以前我一直把 Playwright 当成测试工具。

但这次折腾完之后,我更愿意把它理解成:

一个能够接入真实浏览器会话的自动化控制器。

尤其是在需要:

  • 复用登录态
  • 操作真实页面
  • 连接人工流程和自动化流程

的时候,体验非常顺畅。

很多自动化问题,本质上并不是操作网页难。

而是登录、会话、验证码太麻烦。

而 CDP 接管浏览器,恰好绕开了这些问题。


总结

如果你需要操作一个已经登录的网站,又不想重新实现整套登录流程,可以试试下面这套方案:

浏览器开启远程调试端口
↓
获取 CDP 地址
↓
Playwright connectOverCDP()
↓
连接已有浏览器会话
↓
新开标签页执行自动化任务

这套流程一旦跑通,你会发现很多原本麻烦的事情突然变简单了。

至少对我来说,它比每次从一个全新的浏览器开始要顺手得多。

标签: #工具

评论

无需注册,填写昵称即可评论 阅读 — 次