Go语言:selenium使用与封装

Go语言:selenium使用与封装,第1张

一、 前言
相信大家对于Selenium这个库并不陌生, 一个叱咤风云十年之久的UI自动化框架 很多人都会或多或少的使用过它 python或是java
今天也突发奇想,selenium既然已经支持了如此多的语言 那么Go语言中是否存在这个 *** 作浏览器的库呢?
抱着疑惑 打开了github.com

tebeka/selenium 1.8K的星目前使用率排行第一的三方库
不出意外那就是要出意外
1.8K的使用率代表的就是教程极少只能通过github官方文档 或源码去进行学习 接下来将分享我在本次学习过程中 趟过的坑 以及和python方法进行对比 加深认知

二、安装
	1. 安装selenium-go
		go get github.com/tebeka/selenium 
	2. 安装重要依赖
		首先需要安装seleniu-server.jar的依赖包 这个包将完成selenium的通信工作, 
		如不安装 在运行过程中 将出现 405报错
		selenium-server-standalone-3.141.59.jar
		下载地址 [https://github.com/adamhooper/selenium-server-standalone-jar/tree/master/jar](https://github.com/adamhooper/selenium-server-standalone-jar/tree/master/jar)
	2. 安装webdriver:
		selenium依赖驱动 大家在百度下载和各自浏览器相匹配的版本即可
		Chrome:chromedriver.exe
		firefox: geckodriver.exe
三、使用
	写注释是一个好的习惯
package main

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

const (
	// seleniumJar包存放位置
	SeleniumPath = "F:\tools\geckodriver\selenium-server-standalone-3.141.59.jar"
	// 驱动存放位置
	FireFox      = "F:\tools\geckodriver\geckodriver.exe"
	// 打开 *** 作浏览器的名称(名称与驱动一致)
	BrowserName  = "firefox"
	// 端口
	Port         = 9091
)
// 用于管理服务配置
type ServiceConfig struct {
	SeleniumPath string
	Port         int
	Config       []selenium.ServiceOption
	SetDebug     bool
}
// 用于管理步骤
type CaseMrg struct {
	BySelect, Element string
	MethodName        string
	Timeout           time.Duration
	Value             []reflect.Value
}
// 用于管理driver
type WebDriver struct {
	Driver selenium.WebDriver
}

// 添加服务选项
func (s *ServiceConfig) AddServiceOption(opt ...selenium.ServiceOption) {
	s.Config = append(s.Config, opt...)
}

// Get方法
func (d WebDriver) Get(url string) error {
	return d.Driver.Get(url)
}
// 退出浏览器方法
func (d WebDriver) QuitBrowser() error {
	return d.Driver.Quit()
}
// 构造函数 初始化配置
func NewServiceConfig(seleniumPath string, Port int, setDebug bool) ServiceConfig {
	return ServiceConfig{
		SeleniumPath: seleniumPath,
		Port:         Port,
		Config:       append(([]selenium.ServiceOption)(nil)),
		SetDebug:     setDebug,
	}
}
// 构造函数 初始化服务
func NewService(config ServiceConfig) *selenium.Service {
	selenium.SetDebug(config.SetDebug)
	service, err := selenium.NewSeleniumService(config.SeleniumPath, config.Port, config.Config...)
	if err != nil {
		panic(err)
	}
	return service
}
// 构造函数 初始化driver,和服务
func NewWebDriver(config ServiceConfig, browser string) (service *selenium.Service, w WebDriver, err error) {
	service = NewService(config)
	opt := selenium.Capabilities{"browserName": browser}
	w.Driver, err = selenium.NewRemote(opt, fmt.Sprintf("http://localhost:%d/wd/hub", config.Port))
	if err != nil {
		panic(err)
	}
	return service, w, nil
}
/* 轮询等待 二次封装 
等待元素可见与python中的wait.until一致
 WebDriverWait(self.driver, timeout=timeout).until(lambda x: x.find_element(("id", el)), message=msg)
 */
func WaitElementTimeout(d WebDriver, timeout time.Duration, by, value string) error {
	var IsElementDisplay = func(wd selenium.WebDriver) (bool, error) {
		ele, err := wd.FindElement(by, value)
		if err != nil {
			return false, err
		}
		b, errs := ele.IsDisplayed()
		if errs != nil {
			return false, err
		}
		return b, nil

	}
	if err := d.Driver.WaitWithTimeoutAndInterval(IsElementDisplay, timeout, 500*time.Millisecond); err != nil {
		return err
	}
	return nil
}
// 管理步骤
func NewSliceMrg(names []string, BySelect, Ele []string, timeout time.Duration) []CaseMrg{
	DataList := make([]CaseMrg, 0)
	if len(names) >= 1 {
		for i, v := range names {
			d := CaseMrg{
				BySelect:   BySelect[i],
				Element:    Ele[i],
				MethodName: v,
				Timeout:    timeout,
				Value:      []reflect.Value{reflect.ValueOf(BySelect[i]), reflect.ValueOf(Ele[i])},
			}
			DataList = append(DataList, d)
		}
	}
	return DataList

}
// 通过反射拿到方法名称然后执行
func exeCommand(v reflect.Value, methodsName string, val []reflect.Value) []reflect.Value {
	m := v.MethodByName(methodsName)
	return m.Call(val)
}
// 执行用例
func Run(d WebDriver, dr CaseMrg) error {
	// 反射
	rfv := reflect.ValueOf(d.Driver)
	// 等待元素出现
	if err := WaitElementTimeout(d, 50*time.Second, dr.BySelect, dr.Element); err != nil {
		fmt.Println("等待超時:", err)
		time.Sleep(10 * time.Second)
		return err
	}
	// 执行
	result := exeCommand(rfv, dr.MethodName, dr.Value)
	// 打印返回数据(selenium.Element func)
	fmt.Println(result[0])
	return nil
}

func main() {
	// 测试一下. 首先配置服务选项
	opt := []selenium.ServiceOption{
		selenium.Output(os.Stderr), // 内容输出 这里是标准输出到控制台
		selenium.GeckoDriver(FireFox), // 配置火狐驱动地址 chrome参考官网
	}
	// chrome请参考一下官方文档. 有部份不同
	config := NewServiceConfig(SeleniumPath, Port, false) // 创建服务配置
	config.AddServiceOption(opt...) // 添加
	service, driver, _ := NewWebDriver(config, BrowserName) // 创建驱动
	defer service.Stop() // 延时停止服务
	const url = "https://www.baidu.com" // 请求地址
	driver.Get(url) // 打开浏览器并加载地址
	defer driver.QuitBrowser() // 延时关闭浏览器
	s := NewSliceMrg([]string{"FindElement"}, []string{selenium.ByID}, []string{"kw"}, 20) // 多步骤管理
	for _, v := range s {
	// 执行步骤
		if err := Run(driver, v); err != nil {
			fmt.Println(err)
		}
	}

}

四、总结
相对来说,Go语言社区活跃并无python社区人数多 且该库使用率不高(目前selenium-go排行最高)与其生态有关 导致教程皆是基础教程 所以如果想要了解更多的应用 建议从官方库以及源码解读入手,同时该框架暂不支持鼠标事件(或者我暂时还没看到) 希望未来可以更加完善

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/917175.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存