你是否遇到过浏览器自动化任务启动慢、崩溃频繁或代理管理混乱的问题?
本文带你手把手打造 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 + 任务监控
五、源码地址
- GitHub: github.com/louis-xie-p…
- Gitee: gitee.com/louis_xie/p…
💡 总结:
本文分享了一个 Go + Playwright 高性能自动化框架,实现了 千级任务并发、浏览器复用、任务监控与 Proxy 管理,适用于生产环境,支持 WebUI 与 Prometheus 指标可视化。