Go + Playwright 打造高性能浏览器自动化框架:轻松实现千级并发任务调度!

125 阅读2分钟

你是否遇到过浏览器自动化任务启动慢、崩溃频繁或代理管理混乱的问题?
本文带你手把手打造 Go + Playwright 高性能自动化框架,实现:

  • 千级并发任务调度
  • 浏览器上下文池化复用
  • 智能 Proxy 管理
  • 任务超时与 Watchdog 监控
  • Prometheus 监控 + WebUI 管理

让你用 Go 轻松搭建可扩展、稳定的生产级浏览器自动化服务!


📖 公众号排版优化版正文


一、项目背景

在传统浏览器自动化中,常见痛点:

  • 每个任务都启动新浏览器,内存占用高
  • 浏览器任务阻塞或崩溃时,缺乏监控
  • 多代理、多上下文管理复杂
  • 缺乏任务超时与重试策略

💡 解决方案:基于 Go + Playwright 构建生产级框架,核心特点:

  • ✅ BrowserContext 池化
  • ✅ Proxy 轮询与管理
  • ✅ TaskRunner 调度 + Watchdog
  • ✅ Prometheus 指标监控
  • ✅ WebUI 可视化管理

插入示意图:浏览器池、任务队列、WebUI、Prometheus 指标图


二、项目结构

Playwright-go-crossbrowser-template/
├── main.go
├── types.go
├── browser_pool.go
├── context_pool.go
├── task_runner.go
├── metrics.go
├── metrics_ext.go
├── logging.go
├── profile_pool.go
├── webui.go
├── docker-compose.yml
├── prometheus/
│   └── prometheus.yml
├── grafana/
│   └── dashboard.json
└── README.md
  • browser_pool.go:浏览器实例 + Context 池管理
  • context_pool.go:Context 池化复用
  • task_runner.go:任务调度、超时、重试
  • webui.go:任务队列监控、代理管理
  • metrics_ext.go:Prometheus 指标

三、核心实现

1️⃣ BrowserContext 池化

type ContextWrapper struct {
    Ctx      playwright.BrowserContext
    Busy     bool
    LastUsed time.Time
}

type ContextPool struct {
    mu       sync.Mutex
    browser  playwright.Browser
    contexts []*ContextWrapper
    maxCtx   int
}

func (p *ContextPool) Rent() (playwright.BrowserContext, error) {
    p.mu.Lock()
    defer p.mu.Unlock()
    for _, cw := range p.contexts {
        if !cw.Busy {
            cw.Busy = true
            cw.LastUsed = time.Now()
            return cw.Ctx, nil
        }
    }
    if len(p.contexts) < p.maxCtx {
        c, _ := p.browser.NewContext()
        cw := &ContextWrapper{Ctx: c, Busy: true, LastUsed: time.Now()}
        p.contexts = append(p.contexts, cw)
        return c, nil
    }
    return nil, errors.New("no available contexts")
}
  • Context 池化复用,提高启动速度
  • 自动更新使用时间,用于空闲回收

2️⃣ TaskRunner + Watchdog

func (tr *TaskRunner) executeTask(t task, workerID int) {
    attempts := 0
    for attempts < tr.MaxRetries {
        attempts++
        ctxObj, idx, err := tr.BrowserPool.RentContext()
        ctx, cancel := context.WithTimeout(context.Background(), tr.TaskTimeout)
        page, _ := ctxObj.NewPage()

        done := make(chan struct{})
        go func() {
            select {
            case <-done:
            case <-time.After(tr.HardTimeout):
                page.Close()
                cancel()
            }
        }()

        err = t(ctx, page)
        close(done)
        page.Close()
        cancel()
        tr.BrowserPool.ReturnContext(CtxRef{BrowserIndex: idx, Ctx: ctxObj})

        if err == nil { return }
        time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))
    }
}
  • 支持任务超时、硬超时、重试
  • Watchdog 自动关闭阻塞页面
  • 可统计任务耗时、重试次数

3️⃣ ProxyPool 轮询

type ProxyPool struct {
    proxies []string
    idx     int
}

func (p *ProxyPool) Pick() string {
    if len(p.proxies) == 0 { return "" }
    proxy := p.proxies[p.idx%len(p.proxies)]
    p.idx++
    return proxy
}
  • 多代理轮询
  • 可扩展健康检查、失效剔除

4️⃣ WebUI 接口

r.GET("/health", func(c *gin.Context){
    c.JSON(200, gin.H{"status":"ok"})
})
r.POST("/enqueue", func(c *gin.Context){
    tasks <- func(ctx context.Context, page playwright.Page) error { return nil }
    c.JSON(200, gin.H{"status":"enqueued"})
})
  • 健康检查 /health
  • 任务入队 /enqueue
  • 可扩展代理状态监控

5️⃣ Prometheus 指标

var TaskDuration = prometheus.NewHistogram(
    prometheus.HistogramOpts{
        Name: "automation_task_duration_seconds",
        Help: "Task duration histogram",
    })

func StartMetricsServer(addr string){
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(addr, nil)
}
  • 任务耗时、重试次数统计
  • Grafana 可视化

插入示意图:Prometheus + Grafana 仪表盘示意


四、运行示例

go mod tidy
go run main.go
# WebUI: http://localhost:8080
# Prometheus: http://localhost:9090/metrics
  • 多 worker 高并发任务
  • Proxy 轮询 + Context 池化
  • Watchdog + 任务监控

image.png


五、源码地址


💡 总结
本文分享了一个 Go + Playwright 高性能自动化框架,实现了 千级任务并发、浏览器复用、任务监控与 Proxy 管理,适用于生产环境,支持 WebUI 与 Prometheus 指标可视化。