golang跨浏览器自动化控制插件库playwright-go的使用

Golang跨浏览器自动化控制插件库playwright-go的使用

Playwright是一个Go库,可以通过单一API自动化Chromium、Firefox和WebKit浏览器。Playwright旨在实现跨浏览器网页自动化,具有常青强大可靠快速的特点。

支持的浏览器和平台

浏览器 Linux macOS Windows
Chromium 136.0.7103.25
WebKit 18.4
Firefox 137.0

所有平台上的所有浏览器都支持无头(headless)执行模式。

安装

安装playwright-go库:

go get -u github.com/playwright-community/playwright-go

安装Playwright驱动和浏览器(如果提供--with-deps参数会同时安装操作系统依赖)。注意需要将版本号0.xxxx.x替换为你当前go.mod中使用的版本。每个次要版本升级都需要特定的Playwright驱动版本。

go run github.com/playwright-community/playwright-go/cmd/playwright@v0.xxxx.x install --with-deps
# 或者
go install github.com/playwright-community/playwright-go/cmd/playwright@v0.xxxx.x
playwright install --with-deps

或者,你也可以在代码中下载驱动和浏览器。但如果你的操作系统缺少这些浏览器依赖,仍然需要手动安装,因为安装系统依赖需要权限。

err := playwright.Install()

功能特性

Playwright旨在自动化单页应用(SPA)和渐进式网页应用(PWA)所使用的广泛且不断增长的网页浏览器功能:

  • 跨多个页面、域名和iframe的场景
  • 在执行操作(如点击、填充)前自动等待元素准备就绪
  • 拦截网络活动以存根和模拟网络请求
  • 模拟移动设备、地理位置、权限
  • 通过shadow-piercing选择器支持Web组件
  • 鼠标和键盘的原生输入事件
  • 上传和下载文件

示例代码

以下示例爬取Hacker News当前最受欢迎的条目:

package main

import (
	"fmt"
	"log"

	"github.com/playwright-community/playwright-go"
)

func main() {
	pw, err := playwright.Run()
	if err != nil {
		log.Fatalf("could not start playwright: %v", err)
	}
	browser, err := pw.Chromium.Launch()
	if err != nil {
		log.Fatalf("could not launch browser: %v", err)
	}
	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}
	if _, err = page.Goto("https://news.ycombinator.com"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}
	entries, err := page.Locator(".athing").All()
	if err != nil {
		log.Fatalf("could not get entries: %v", err)
	}
	for i, entry := range entries {
		title, err := entry.Locator("td.title > span > a").TextContent()
		if err != nil {
			log.Fatalf("could not get text content: %v", err)
		}
		fmt.Printf("%d: %s\n", i+1, title)
	}
	if err = browser.Close(); err != nil {
		log.Fatalf("could not close browser: %v", err)
	}
	if err = pw.Stop(); err != nil {
		log.Fatalf("could not stop Playwright: %v", err)
	}
}

更多示例

  • 下载文件
  • 网站端到端测试
  • 在浏览器中执行JavaScript
  • 模拟移动设备和地理位置
  • 使用WaitGroup进行并行爬取
  • 将网站渲染为PDF
  • 爬取HackerNews
  • 截图
  • 录制视频
  • 监控网络活动

工作原理

Playwright是一个Node.js库,它使用:

  • Chrome DevTools协议与Chromium通信
  • 补丁版Firefox与Firefox通信
  • 补丁版WebKit与WebKit通信

这些补丁基于浏览器的原始源代码,不会修改浏览器行为,因此浏览器基本上与你在野外看到的相同。对不同编程语言的支持基于在Node.js领域公开RPC服务器,这允许其他语言使用Playwright而无需实现所有自定义逻辑。

Node.js和其他语言之间的桥梁基本上是一个与Playwright结合的Node.js运行时,为每种语言(约50MB)提供,然后通过stdio通信发送相关命令。这也会下载预编译的浏览器。

资源

  • Playwright for Go文档
  • Playwright文档
  • 示例配方

更多关于golang跨浏览器自动化控制插件库playwright-go的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang跨浏览器自动化控制插件库playwright-go的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Playwright-go: Golang跨浏览器自动化控制库

Playwright-go是Microsoft Playwright的Golang绑定,它允许你通过代码自动化控制Chromium、Firefox和WebKit浏览器,实现端到端的测试和网页自动化操作。

安装Playwright-go

首先需要安装Playwright-go库:

go get github.com/playwright-community/playwright-go

然后安装所需的浏览器二进制文件:

go run github.com/playwright-community/playwright-go/cmd/playwright install

基本使用示例

1. 启动浏览器并访问页面

package main

import (
	"log"

	"github.com/playwright-community/playwright-go"
)

func main() {
	pw, err := playwright.Run()
	if err != nil {
		log.Fatalf("could not start playwright: %v", err)
	}
	defer pw.Stop()

	browser, err := pw.Chromium.Launch()
	if err != nil {
		log.Fatalf("could not launch browser: %v", err)
	}
	defer browser.Close()

	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}

	if _, err = page.Goto("https://example.com"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}

	title, err := page.Title()
	if err != nil {
		log.Fatalf("could not get title: %v", err)
	}
	log.Printf("Page title: %s", title)
}

2. 填写表单并提交

func fillForm() {
	// ...前面的初始化代码同上...

	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}

	if _, err = page.Goto("https://example.com/login"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}

	// 填写用户名和密码
	if err = page.Locator("#username").Fill("testuser"); err != nil {
		log.Fatalf("could not fill username: %v", err)
	}
	if err = page.Locator("#password").Fill("password123"); err != nil {
		log.Fatalf("could not fill password: %v", err)
	}

	// 点击登录按钮
	if err = page.Locator("button[type='submit']").Click(); err != nil {
		log.Fatalf("could not click submit button: %v", err)
	}

	// 等待导航完成
	page.WaitForNavigation()
}

3. 截图和PDF生成

func takeScreenshotAndPDF() {
	// ...初始化代码...
	
	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}

	if _, err = page.Goto("https://example.com"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}

	// 截图
	if _, err = page.Screenshot(playwright.PageScreenshotOptions{
		Path: playwright.String("screenshot.png"),
	}); err != nil {
		log.Fatalf("could not take screenshot: %v", err)
	}

	// 生成PDF
	pdfData, err := page.PDF(playwright.PagePdfOptions{
		Path: playwright.String("page.pdf"),
	})
	if err != nil {
		log.Fatalf("could not generate PDF: %v", err)
	}
	log.Printf("Generated PDF with %d bytes", len(pdfData))
}

高级功能

1. 处理iframe

func handleIframe() {
	// ...初始化代码...
	
	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}

	if _, err = page.Goto("https://example.com/iframe-page"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}

	// 获取iframe
	frame := page.Frame("iframe-name")
	if frame == nil {
		frame = page.FrameByURL("https://example.com/iframe-content")
	}

	// 在iframe内操作
	if frame != nil {
		if err = frame.Locator("#iframe-button").Click(); err != nil {
			log.Fatalf("could not click iframe button: %v", err)
		}
	}
}

2. 模拟移动设备

func emulateMobile() {
	// ...初始化代码...
	
	iphone := playwright.Devices["iPhone 11"]
	context, err := browser.NewContext(playwright.BrowserNewContextOptions{
		Viewport:    iphone.Viewport,
		UserAgent:   iphone.UserAgent,
		DeviceScaleFactor: iphone.DeviceScaleFactor,
		IsMobile:    iphone.IsMobile,
		HasTouch:    iphone.HasTouch,
	})
	if err != nil {
		log.Fatalf("could not create context: %v", err)
	}
	defer context.Close()

	page, err := context.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}

	if _, err = page.Goto("https://example.com"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}
}

3. 网络拦截和模拟

func interceptRequests() {
	// ...初始化代码...
	
	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}

	// 拦截所有请求
	err = page.Route("**/*", func(route playwright.Route) {
		// 屏蔽图片请求
		if route.Request().ResourceType() == "image" {
			route.Abort()
		} else {
			route.Continue()
		}
	})
	if err != nil {
		log.Fatalf("could not set up route: %v", err)
	}

	if _, err = page.Goto("https://example.com"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}
}

测试示例

Playwright-go非常适合用于端到端测试:

func TestLogin(t *testing.T) {
	pw, err := playwright.Run()
	if err != nil {
		t.Fatalf("could not start playwright: %v", err)
	}
	defer pw.Stop()

	browser, err := pw.Chromium.Launch()
	if err != nil {
		t.Fatalf("could not launch browser: %v", err)
	}
	defer browser.Close()

	page, err := browser.NewPage()
	if err != nil {
		t.Fatalf("could not create page: %v", err)
	}

	if _, err = page.Goto("http://localhost:8080/login"); err != nil {
		t.Fatalf("could not goto: %v", err)
	}

	// 测试登录流程
	if err = page.Locator("#username").Fill("testuser"); err != nil {
		t.Fatalf("could not fill username: %v", err)
	}
	if err = page.Locator("#password").Fill("password123"); err != nil {
		t.Fatalf("could not fill password: %v", err)
	}
	if err = page.Locator("button[type='submit']").Click(); err != nil {
		t.Fatalf("could not click submit button: %v", err)
	}

	// 验证登录成功
	if _, err = page.WaitForSelector(".welcome-message"); err != nil {
		t.Fatalf("login failed: %v", err)
	}
}

总结

Playwright-go提供了强大的跨浏览器自动化能力,主要特点包括:

  • 支持Chromium、Firefox和WebKit
  • 自动等待元素出现和可操作状态
  • 强大的选择器和定位器API
  • 网络拦截和模拟功能
  • 设备模拟和移动端测试
  • 截图和PDF生成

相比传统的Selenium方案,Playwright-go具有更好的性能和更现代的API设计,非常适合用于自动化测试和网页抓取等场景。

回到顶部