Playwright 复用本机 Chrome:省掉 170MB 下载,以及三个 cookie 注入坑

举报
yd_264066207 发表于 2026/10/31 23:01:52 2026/10/31
【摘要】 在服务器或 CI 里跑 Playwright,最容易卡住的一步不是写脚本,而是浏览器二进制。默认安装会拉一个约 170MB 的 Chromium,网络一抖就失败。其实机器上已经有 Chrome 时,完

在服务器或 CI 里跑 Playwright,最容易卡住的一步不是写脚本,而是浏览器二进制。默认安装会拉一个约 170MB 的 Chromium,网络一抖就失败。其实机器上已经有 Chrome 时,完全可以复用它。

一、优先用系统浏览器

playwright-go 的 Launch 支持 ExecutablePath。写一个探测函数,按平台找:

func chromePath() string {
    for _, p := range []string{
        "/usr/bin/chromium",
        "/usr/bin/google-chrome",
        "/snap/bin/chromium",
    } {
        if _, err := os.Stat(p); err == nil {
            return p
        }
    }
    for _, base := range []string{
        os.Getenv("ProgramFiles"),
        os.Getenv("LOCALAPPDATA"),
    } {
        if base == "" {
            continue
        }
        p := filepath.Join(base, "Google", "Chrome", "Application", "chrome.exe")
        if _, err := os.Stat(p); err == nil {
            return p
        }
    }
    return ""
}

找到就传进去,找不到再回落到 Playwright 自带 Chromium:

opts := playwright.BrowserTypeLaunchOptions{Headless: playwright.Bool(true)}
if p := chromePath(); p != "" {
    opts.ExecutablePath = playwright.String(p)
}
browser, err := pw.Chromium.Launch(opts)

注意:driver 仍然要装。省掉的是浏览器本体,不是 Node 侧的 driver。

二、__Host- 前缀的 cookie 会导致整批注入失败

把登录态导出后塞进新 context 是常见做法。但一批 cookie 里只要有一个不合法,AddCookies 会整体报错:

playwright: Protocol error (Storage.setCookies): Invalid cookie fields

罪魁祸首通常是 __Host-session 这类名字。按规范,__Host- 前缀必须满足三条:不带 domain、path 为 /、标记 Secure。从浏览器导出时它带着 domain,直接回填就会被拒。

解决办法是改用 url 表达,让 Playwright 自己推导 domain 与 path:

if strings.HasPrefix(c.Name, "__Host-") {
    item.URL = playwright.String("https://" + host + "/")
    item.Secure = playwright.Bool(true)
    continue
}
item.Domain = playwright.String(c.Domain)
item.Path = playwright.String(c.Path)

三、批量失败要退化成逐个注入

即使修好 __Host-,生产环境的 cookie 依然可能有个别异常。批量注入失败时不要直接放弃,逐个再试一遍,跳过坏的:

func addCookies(ctx playwright.BrowserContext, cookies []playwright.OptionalCookie) error {
    if len(cookies) == 0 {
        return nil
    }
    if err := ctx.AddCookies(cookies); err == nil {
        return nil
    }
    ok := 0
    var firstErr error
    for _, c := range cookies {
        if err := ctx.AddCookies([]playwright.OptionalCookie{c}); err != nil {
            if firstErr == nil {
                firstErr = fmt.Errorf("cookie %s: %w", c.Name, err)
            }
            continue
        }
        ok++
    }
    if ok == 0 && firstErr != nil {
        return firstErr
    }
    return nil
}

这样即使丢掉两三个 cookie,登录态通常还能用。

四、多子域同名 cookie 别按 name 去重

如果目标站点跨多个子域,同名 cookie 会同时出现好几份,值还不一样。按 name 去重只保留最后一条,很可能留下的是过期副本。

正确做法是按 (domain, path, name) 三元组区分,或者干脆不去重,交给浏览器自己判定优先级。

小结

问题 处理
不想下载 170MB Chromium ExecutablePath 指向系统 Chrome
Invalid cookie fields __Host- 前缀改用 url 表达
一个坏 cookie 拖垮全部 批量失败后逐个注入
同名 cookie 取值错乱 按 domain + path + name 去重

复用系统浏览器除了省下载,还有个隐性好处:指纹更接近真实用户,不容易被判定为机器人。代价是版本不受控,升级 Chrome 后要及时回归。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。