别再用复制 Cookie 了:用 CDP 接管已登录的 Chrome 做自动化
摘要
需要登录态的网页自动化,最容易踩的坑不是选择器,而是"登录"本身:直接复制 Chrome 的 Cookies 文件大概率失效,重新登录又卡在短信验证码。本文记录一次真实排查——从复制 Cookie 失败,到用 --remote-debugging-port + connect_over_cdp 接管已登录浏览器的完整过程和代码。
一、问题:自动化的第一步就卡住了
需求是驱动一个已登录的网页做批量操作。直觉方案是"把浏览器现有登录态搬过来",于是先试了最省事的一条路:
复制 <User Data>\Local State
复制 <User Data>\Default\Network\Cookies
放进一个新的 user-data-dir
结果打开目标站点,直接跳登录页。Cookie 文件确实复制过去了(能读到 14 条),但会话不在里面。
原因是 Chrome 在 127 之后对 Cookie 引入了 App-Bound Encryption:密钥不再只由 DPAPI 保护,还和浏览器可执行文件路径绑定。把 Cookies 数据库搬到另一个进程上下文里,解不开。
二、第二方案:让浏览器自己开个"调试口"
既然搬登录态不可行,那就反过来——不搬,直接接管那个已经登录的浏览器实例。
关键只有两个参数:
chrome.exe --remote-debugging-port=9222 \
--user-data-dir="<一个非默认目录>"
要点:
1. --remote-debugging-port 只在进程首次启动时生效。如果该 user-data-dir 已经有 Chrome 在跑,新命令只会把请求转交给现有进程,端口不会打开。所以必须用一个独立目录,或者先退出原有实例。
2. 从 Chrome 136 起,调试端口不允许配合默认的 user-data-dir 使用,必须显式指定另一个目录。
启动后确认端口活着:
curl http://127.0.0.1:9222/json/version
返回 webSocketDebuggerUrl 就说明可以连了。
三、接管:三行代码进入已登录页面
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp("http://127.0.0.1:9222")
ctx = browser.contexts[0]
page = [x for x in ctx.pages if "target.site" in x.url][-1]
connect_over_cdp 的最大价值是进程解耦:脚本跑完退出,浏览器还活着,登录态和已打开的业务页面都留着。下一步脚本再连上来接着干,不用反复登录。
代价是要自己管理标签页——ctx.pages 里会混着之前打开的所有窗口,务必按 URL 过滤后取最后一个,而不是无脑用 ctx.pages[0]。
四、几个真实踩过的坑
1. 点击任务卡片的按钮点到了隔壁
列表页里每张卡片都有一个同名按钮(比如都是"去完成")。用 get_by_text("去完成").first 会命中第一张卡片;按标题找卡片时如果往上爬到公共容器,又会匹配到整个网格。
稳妥写法是"最小容器":对每个候选按钮,向上找最近的、内部文本包含标题的祖先,然后取文本长度最小的那个。
for (const b of btns) {
let n = b.parentElement, depth = 0;
while (n && depth++ < 10) {
if (n.innerText.includes(title)) { pickSmallest(n); break; }
n = n.parentElement;
}
}
2. 点了链接,URL 却纹丝不动
SPA 的卡片按钮通常没有 href,点击走的是框架路由。用 page.click() 有时因为过渡动画、遮罩层拦截而"点了个寂寞",URL 不变也不报错。
判断方法:点完打印 page.url。如果没变,别纠缠点击,直接 page.goto() 到目标地址,再确认页面标题符合预期。
3. 新手引导遮罩吃掉所有点击
首次访问某站会弹 4 步引导,.spotlight-guide 铺满全屏,所有点击都被它截获。报错长这样:
<div class="spotlight-guide"> subtree intercepts pointer events
处理方式是先把引导走完(点"下一步"直到出现"完成"),不要试图 force=True 硬点——那只是骗过了 Playwright,事件还是被遮罩收走。
4. 解释器不一致导致 ModuleNotFoundError
Windows 上装了多个 Python 时,pip install playwright 和 python script.py 可能不是同一个解释器。装完却 import 失败,先确认:
python -c "import sys; print(sys.executable)"
再决定用哪个解释器跑脚本。
五、什么时候该用这个方案
适合:需要长期保持登录态、有短信/扫码等强验证、操作有真人语义(点任务、填表单、看页面状态)。
不适合:纯数据抓取。那种场景用无头浏览器 + 独立 Cookie 更干净,也不必惊动用户的桌面。
六、一点提醒
接管用户浏览器意味着能看到他所有的标签页和登录态。这条权限很重:只做用户明确要求的事,不要顺手读别的页面;涉及授权(比如同步云凭据)、公开发布(比如提 Issue、发文章)的动作,先问再做。
自动化省下的是重复劳动,不该省掉的是判断。
- 点赞
- 收藏
- 关注作者
评论(0)