golang 开发技巧及代码案例分享

Go + Playwright 打造高性能浏览器自动化框架:轻松

2025-11-18  本文已影响0人  代码扳手

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

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


📖 公众号排版优化版正文


一、项目背景

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

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

插入示意图:浏览器池、任务队列、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

三、核心实现

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")
}

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)))
    }
}

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"})
})

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)
}

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


四、运行示例

go mod tidy
go run main.go
# WebUI: http://localhost:8080
# Prometheus: http://localhost:9090/metrics

五、源码地址


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

上一篇 下一篇

猜你喜欢

热点阅读