GolangNote

Golang笔记

golang Selenium WebDriver 使用记录

Permalink

Selenium WebDriver 直接通过浏览器自动化的本地接口来调用浏览器,以达到模拟浏览器行为的操作,如点击、选择、鼠标移动等。下面是记录个人使用golang 驱动的记录。

下载Selenium 驱动

Selenium 官网 https://www.seleniumhq.org 在那可以下载对应浏览器的驱动。你可以下载一个jar 包 Selenium Standalone Server 这个比较方便,可以运行在多个不同平台,但需要计算机有java 运行环境。

也可以根据自己的需求下载特定浏览器的驱动,如 The Internet Explorer Driver ServerMozilla GeckoDriverGoogle Chrome Driver 等,这都是二进制文件,可以单独运行,不依赖java 环境。

Selenium 浏览器驱动

选择 golang 驱动

这个库是目前比较完善的 golang Selenium 驱动 https://github.com/tebeka/selenium,但官方没有IeDriverService,这里我做一个补充,在 service.go 里面添加一个函数:

Go: DriverService
1
2
3
4
5
6
7
8
9
10
11
func NewIeDriverService(path string, port int, opts ...ServiceOption) (*Service, error) {
	cmd := exec.Command(path, "--port="+strconv.Itoa(port))
	s, err := newService(cmd, port, opts...)
	if err != nil {
		return nil, err
	}
	if err := s.start(port); err != nil {
		return nil, err
	}
	return s, nil
}

这样就可以在外部调用:

Go: IEDriverServer
1
2
3
4
service, err := selenium.NewIeDriverService("IEDriverServer.exe", port, opts...)
if err != nil {
	panic(err)
}

使用动态端口

因为启动 DriverService 需要占用一个端口,防止指定端口已经被占用,可以用下面的函数来动态获取一个可用端口。

Go: 动态端口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func pickUnusedPort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
	if err != nil {
		return 0, err
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	port := l.Addr().(*net.TCPAddr).Port
	if err := l.Close(); err != nil {
		return 0, err
	}
	return port, nil
}

完整例子

下面是在官方例子上做了一点修改,使用ieDriver的例子:

Go: selenium 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main

import (
	"fmt"
	"github.com/tebeka/selenium"
	"net"
	"os"
	"time"
)

func pickUnusedPort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
	if err != nil {
		return 0, err
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	port := l.Addr().(*net.TCPAddr).Port
	if err := l.Close(); err != nil {
		return 0, err
	}
	return port, nil
}

func main() {
	port, err := pickUnusedPort()
	fmt.Println("port", port)

	opts := []selenium.ServiceOption{
		selenium.Output(os.Stderr),
	}
	selenium.SetDebug(false)

	service, err := selenium.NewIeDriverService("IEDriverServer.exe", port, opts...)
	if err != nil {
		panic(err)
	}
	defer service.Stop()

	fmt.Println("here 1")

	// 起新线程在新标签页打开窗口
	go func() {
		caps := selenium.Capabilities{"browserName": "internet explorer"}
		wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d", port))
		if err != nil {
			panic(err)
		}
		defer wd.Quit()

		if err := wd.Get("https://www.baidu.com"); err != nil {
			panic(err)
		}

		time.Sleep(time.Second * 10)

		// 在窗口调用js 脚本
		wd.ExecuteScript(`window.open("https://www.qq.com", "_blank");`, nil)

		time.Sleep(time.Second * 20)
	}()

	// 打开一个在一个标签页里打开一个窗口
	caps := selenium.Capabilities{"browserName": "internet explorer"}
	wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d", port))
	if err != nil {
		panic(err)
	}
	defer wd.Quit()

	// Navigate to the simple playground interface.
	if err := wd.Get("http://play.golang.org/?simple=1"); err != nil {
		panic(err)
	}

	// Get a reference to the text box containing code.
	elem, err := wd.FindElement(selenium.ByCSSSelector, "#code")
	if err != nil {
		panic(err)
	}
	// Remove the boilerplate code already in the text box.
	if err := elem.Clear(); err != nil {
		panic(err)
	}

	// Enter some new code in text box.
	err = elem.SendKeys(`
		package main
		import "fmt"
		func main() {
			fmt.Println("Hello WebDriver!\n")
		}
	`)
	if err != nil {
		panic(err)
	}

	// Click the run button.
	btn, err := wd.FindElement(selenium.ByCSSSelector, "#run")
	if err != nil {
		panic(err)
	}
	if err := btn.Click(); err != nil {
		panic(err)
	}

	// Wait for the program to finish running and get the output.
	outputDiv, err := wd.FindElement(selenium.ByCSSSelector, "#output")
	if err != nil {
		panic(err)
	}

	var output string
	for {
		output, err = outputDiv.Text()
		if err != nil {
			panic(err)
		}
		if output != "Waiting for remote server..." {
			break
		}
		time.Sleep(time.Second * 1)
	}

	fmt.Println("waiting....")
	time.Sleep(time.Second * 80)

	// Example Output:
	// Hello WebDriver!
	//
	// Program exited.
}

注意问题

如果用 Selenium Standalone Server 启动 NewRemote 时,路径不同,应设为:

Go: Remote
1
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))

Related articles

golang snappy 的使用场合

google 自家的 snappy 压缩优点是非常高的速度和合理的压缩率。压缩率比 gzip 小,CPU 占用小。...

Go Modules 使用备忘

简单说 Go Modules 就是包管理,从 go1.11 开始支持,可以不需要gopath存在,环境变量`GO111MODULE`,默认为 `auto` 项目存在 `go.mod` 则使用 go module ,否则使用GOPATH 和 vendor 机制。...

Golang WebAssembly 了解一下

Go 1.11 起开始支持 WebAssembly ,也就是说以后可以使用任何语言作为“前端语言”来进行 Web 开发。...

Write a Comment to "golang Selenium WebDriver 使用记录"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.16.5 Processed in 2ms