Gochromedp教程展示了如何使用chromedp在Golang中自动化浏览器。
chromedp是一个Go库,它提供高级API以通过DevTools协议控制Chromium。它允许在无界面模式(默认模式)下使用浏览器,无需UI。这非常适合编写脚本。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
获取外部HTML
chromedp.OuterHTML检索与选择器匹配的第一个元素节点的外部HTML。
package main
import (
"context"
"fmt"
"log"
"github.com/chromedp/chromedp"
)
func main() {
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
url := "http://webcode.me"
var data string
if err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.OuterHTML("html", &data, chromedp.ByQuery),
); err != nil {
log.Fatal(err)
}
fmt.Println(data)
}
该示例检索webcode.me的主页。
ctx, cancel := chromedp.NewContext(context.Background()) defer cancel()
chromedp.NewContext从父上下文创建一个chromedp上下文。必须调用返回的取消函数来终止chromedp上下文;该函数等待资源被清理,并返回在该过程中遇到的任何错误。
if err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.OuterHTML("html", &data, chromedp.ByQuery),
); err != nil {
log.Fatal(err)
}
Run函数根据上下文运行操作。我们导航到URL并检索html标记的HTML数据。
获取标题
使用chromedp.Title,我们得到文档标题。
package main
import (
"context"
"fmt"
"io"
"log"
"net/http"
"net/http/httptest"
"strings"
"github.com/chromedp/chromedp"
)
func writeHTML(content string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
io.WriteString(w, strings.TrimSpace(content))
})
}
func main() {
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
ts := httptest.NewServer(writeHTML(`
<head>
<title>Home page</title>
</head>
<body>
<p>Hello there!</a>
</body>
`))
defer ts.Close()
var title string
if err := chromedp.Run(ctx,
chromedp.Navigate(ts.URL),
chromedp.Title(&title),
); err != nil {
log.Fatal(err)
}
fmt.Println(title)
}
在示例中,我们创建了发送一个小网页的内置网络服务器。我们检索了它的标题。
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
io.WriteString(w, strings.TrimSpace(content))
})
处理函数将text/html内容发送回客户端。
ts := httptest.NewServer(writeHTML(`
<head>
<title>Home page</title>
</head>
<body>
<p>Hello there!</a>
</body>
`))
使用httptest.NewServer创建测试服务器。
defer ts.Close()
程序结束时,测试服务器关闭。
if err := chromedp.Run(ctx,
chromedp.Navigate(ts.URL),
chromedp.Title(&title),
); err != nil {
log.Fatal(err)
}
我们导航到测试服务器的URL并使用chromedp.Title获取文档标题。
$ go run title.go Home page
设置超时
我们的任务可能会遇到死锁。为了防止它们,我们可以设置超时。
package main
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/chromedp/chromedp"
)
func main() {
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
defer cancel()
url := "http://webcode.me"
var res string
err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.Text("body", &res, chromedp.NodeVisible),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(strings.TrimSpace(res))
}
在示例中,我们获取了body标签的可见文本。设置了超时。
ctx, cancel = context.WithTimeout(ctx, 5*time.Second) defer cancel()
我们将超时设置为5秒。
err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.Text("body", &res, chromedp.NodeVisible),
)
我们运行一个任务列表。我们使用chromedp.Text获取body的文本。
点击动作
使用chromedp.Click执行点击查询操作。
package main
import (
"context"
"log"
"time"
"github.com/chromedp/chromedp"
"github.com/chromedp/chromedp/device"
)
func main() {
ctx, cancel := chromedp.NewContext(
context.Background(),
)
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
defer cancel()
url := "http://webcode.me/click.html"
var ua string
err := chromedp.Run(ctx,
chromedp.Emulate(device.IPhone11),
chromedp.Navigate(url),
chromedp.Click("button", chromedp.NodeVisible),
chromedp.Text("#output", &ua),
)
if err != nil {
log.Fatal(err)
}
log.Printf("User agent: %s\n", ua)
}
在这个例子中,我们点击一个网页的按钮。网页在输出div中显示客户端的用户代理。
err := chromedp.Run(ctx,
chromedp.Emulate(device.IPhone11),
chromedp.Navigate(url),
chromedp.Click("button", chromedp.NodeVisible),
chromedp.Text("#output", &ua),
)
在任务列表中,我们导航到URL,单击按钮,然后检索文本输出。我们得到我们的用户代理。我们使用chromedp.Emulate模拟iPhone11设备。
创建屏幕截图
我们可以使用chromedp.Screenshot创建元素的屏幕截图。chromedp.FullScreenshot获取整个浏览器视口的屏幕截图。
package main
import (
"context"
"fmt"
"io/ioutil"
"log"
"github.com/chromedp/chromedp"
)
func main() {
ctx, cancel := chromedp.NewContext(
context.Background(),
)
defer cancel()
url := "http://webcode.me"
var buf []byte
if err := chromedp.Run(ctx, ElementScreenshot(url, "body", &buf)); err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile("body.png", buf, 0o644); err != nil {
log.Fatal(err)
}
if err := chromedp.Run(ctx, FullScreenshot(url, 90, &buf)); err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile("full.png", buf, 0o644); err != nil {
log.Fatal(err)
}
fmt.Println("screenshots created")
}
func ElementScreenshot(url, sel string, res *[]byte) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate(url),
chromedp.Screenshot(sel, res, chromedp.NodeVisible),
}
}
func FullScreenshot(url string, quality int, res *[]byte) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate(url),
chromedp.FullScreenshot(res, quality),
}
}
我们创建了两个屏幕截图。使用ioutil.WriteFile将图像写入磁盘。
提交表格
chromedp.SendKeys用于填写输入字段。可以使用chromedp.Click或chromedp.Submit.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/chromedp/chromedp"
)
func main() {
ctx, cancel := chromedp.NewContext(
context.Background(),
)
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 6*time.Second)
defer cancel()
url := "http://webcode.me/submit/"
var res string
err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.SendKeys("input[name=name]", "Lucia"),
chromedp.SendKeys("input[name=message]", "Hello!"),
// chromedp.Click("button", chromedp.NodeVisible),
chromedp.Submit("input[name=name]"),
chromedp.Text("*", &res),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(res)
}
示例填写表单并接收消息。
chromedp.SendKeys("input[name=name]", "Lucia"),
chromedp.SendKeys("input[name=message]", "Hello!"),
我们将两个字符串设置为指定的输入标签。
// chromedp.Click("button", chromedp.NodeVisible),
chromedp.Submit("input[name=name]"),
我们可以使用chromedp.Click或chromedp.Submit提交表单。在后一种情况下,该函数提交与选择器匹配的第一个元素节点的父表单。
在本教程中,我们使用带有chromedp的Go自动浏览器。
列出所有Go教程。
