本地把 Chrome 会话复用跑通:cookie 解密 + Playwright 注入的工程实录

1 阅读3分钟

不碰账号密码、不碰 2FA,把本机 Chrome 已登录会话复用到 Playwright,驱动填表/抓数/点按钮。核心三步:Keychain 取 Chrome Safe Storage 口令 → PBKDF2(saltysalt, 1003 轮) 派生密钥 → AES-128-CBC(openssl) 解开 v10 cookie;再用 launchPersistentContext + addCookies 注入全新上下文。

1. cookie 从哪来、怎么解

Chrome 在 macOS 把 cookie 加密存在 ~/Library/Application Support/Google/Chrome/Default/Cookies(SQLite,cookies 表)。加密密钥不落盘,存在系统 Keychain 的 Chrome Safe Storage 项里。

解密函数(脚本 dump_cookies.py,共 88 行)核心是这段:

KEY = hashlib.pbkdf2_hmac("sha1", KEYCHAIN_PW, b"saltysalt", 1003, 16)
IV  = b" " * 16  # 16 个空格
# 去 v10 / v11 三字节前缀
body = enc[3:] if enc[:3] in (b"v10", b"v11") else enc
if enc[:3] == b"v20":
    raise RuntimeError("app-bound encryption (v20) not supported")
# openssl aes-128-cbc -d -nopad 解密,再去 PKCS7

要点:

  • 派生算法固定:PBKDF2(HMAC-SHA1, 口令, saltysalt, 1003, dklen=16);
  • IV 是 16 个空格(b" " * 16),不是随机值;
  • 前缀 v10/v11 是常规加密,v20 是 app-bound encryption,这条路不通,需另想办法;
  • Chrome 130+ 在明文前加 32 字节 domain hash,要剥掉才是真值;
  • 解密用系统 openssl 即可,无需装 pycryptodome。

2. 注入:全新上下文 + 去重

fig4.png 千万不要直接拷贝整个 Chrome profile——实测密钥不匹配会让所有 cookie 解密失败、瞬间全退登录态。正确姿势:

const ctx = await chromium.launchPersistentContext('/tmp/wb-pw-profile', {
  channel: 'chrome', headless: true,
});
const cookies = raw.filter(/* 按 name|domain|path 去重 */);
cookies.forEach(c => c.sameSite = c.sameSite || 'Lax');
await ctx.addCookies(cookies);

要点:

  • 用 launchPersistentContext 起全新临时目录,不是用户日常 Chrome;
  • 注入前按 name|domain|path 三元组去重,重复 cookie 会让站点认不出登录态;
  • sameSite 字段补成合法值(Lax/Strict),否则部分站点读不到;
  • 验证登录看页面文字里的用户名,不要只看 HTTP 200——状态码 200 也可能是跳到了登录页。

3. 表单填表的可靠打法(真实踩坑数字)

控件正确做法错法(静默失败)
Element UI el-cascaderhover 父节点展开子列,再点叶子 .el-cascader-node__label点父节点复选框 → 一次误勾 88 项
Quill 富文本click→Meta+A→删除→keyboard.insertText找 textarea(不存在);fill() 无效
contenteditable同上,用 insertText 而非 fillnative setter + dispatchEvent → model 不更新
antd RangePicker面板点选、跨年双向翻页;无固定期限填 2099-12-31fill() 写进去但 model 不变
提交按钮文案夹空格innerText.replace(/\s+/g,'') 再比 + 坐标点击hasText('提交') → 超时 45s
Nuxt/Vue SPA抓 Vue Router 一次拿 128 条路由猜 URL(/user/123)→ 全 404

通用纪律:行内逐项保存的表单,输入完至少等 1.2–1.8 秒再点保存(实测 0.9 秒静默失败、1.5 秒才稳);最后必须重载页面反查值真的落库。

4. 复现清单

fig5.png

文件行数作用
dump_cookies.py88从 Default/Cookies 解密指定域 cookie → JSON
chrome-session-reuse SKILL.md173cookie 解密 + Playwright 注入 + 表单打法全集
注入上下文—launchPersistentContext + addCookies + sameSite 修正