无法获取iframe框架中的元素
https://github.com/chromedp/chromedp/issues/72
这个问题截止今日2022/10/20还没有被解决,这也是你要使用chromedp前需要考虑清楚的,如果含有嵌套结构chromedp是无法获取到子框架中的元素的!!!
判断元素是否存在
目前我发现的有三种方法:
- chromedp.Evaluate + document.querySelectorAll
chromedp.Evaluate(`document.querySelectorAll("#submit-mfa-btn").length`, &mailPageExist)
其中mailPageExist为[]byte类型
可以从控制台看出,如果没有该元素则返回为0(string类型),有为1
- EvaluteAsDevTool
chromedp.EvaluateAsDevTools(`document.querySelector("body > div.bcapc-popup.bcap-popup.bcapc-popup-lang-en > div")`, &captchaExist)
用法和上面差不多,官方文档中说用这个命令是模拟在控制台中输入信息。如图有值返回js没值返回null
3.Nodes
这是问题check for an element is present in the page中官方给出的解答
chromedp.Nodes(yourSelector, &nodes, chromedp.AtLeast(0))
- chromedp.Evaluate + document.evaluate
这是问题xPath count get data中官方给出的解答
chromedp.Evaluate(`document.evaluate('count(//*[@id="country-additional-info"]/table/tbody/tr)', document).numberValue`, &additionalLen)
问题
有时候获得的结果很奇怪,明明没有这个元素但是有返回值,所以具体什么情况用什么还得自己试试。除此之外读取数据的时候记得转为string类型,因为[48]转换为字符串就是0
鼠标悬浮在指定元素
步骤:
- 获取想要悬浮元素的位置(x,y);
- 利用
input.mousemoved
将鼠标置于(x,y)处.
chromedp.QueryAfter("#kyc-ui > div.style-dialog-body.css-1q3mrho > div.css-gnqbje > div > div > div.css-16vu25q > div.css-5dr7s > div > div.css-1wi4m92 > div > div > div.css-1ggy8dc", func(fctx context.Context, id runtime.ExecutionContextID, node ...*cdp.Node) error {
n := node[0]
return qrScreenshot(n, fctx)
}),
func QrScreenshot(n *cdp.Node, cxt context.Context) error {
boxes, err := dom.GetContentQuads().WithNodeID(n.NodeID).Do(cxt)
if err != nil {
return err
}
if len(boxes) == 0 {
return chromedp.ErrInvalidDimensions
}
content := boxes[0]
c := len(content)
if c%2 != 0 || c < 1 {
return chromedp.ErrInvalidDimensions
}
var x, y float64
for i := 0; i < c; i += 2 {
x += content[i]
y += content[i+1]
}
x /= float64(c / 2)
y /= float64(c / 2)
p := &input.DispatchMouseEventParams{
Type: input.MouseMoved,
X: x,
Y: y,
}
if err := p.Do(cxt); err != nil {
return err
}
return p.Do(cxt)
}
cookie的设置和获取
cookie可以在控制台查看,这里也是利用DevTool中的GetAllCookies和SetCookies来获取和设置cookie
getCookies: https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-getCookies
setCookies: https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setCookies
(PS: 这里介绍一款谷歌插件专门用于管理cookie的叫EditThisCookie,图标很可爱就是一个小饼干,可以通过这个插件查看cookie信息以及导入导出cookie)
获取cookie
其实重点就只有network.GetAllCookies().Do(ctx)
,这段代码是获取p20t和cr00两个cookie
func GetCookies(ctx context.Context) (string, string) {
var cookie model.User
coo, err := network.GetAllCookies().Do(ctx)
if err != nil {
fmt.Println(err)
return "err", ""
}
for _, v := range coo {
if v.Name == "p20t" {
cookie.P20t = v.Value
} else if v.Name == "cr00" {
cookie.Cr00 = v.Value
}
}
return cookie.P20t, cookie.Cr00
}
设置cookie
network.SetCookie(name, value)
,其他相关参数可以在控制台查看,DevTools手册中也有具体解释:https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-setCookie
func SetCookies(name string, value string, domain string, httpOnly bool, secure bool, sameSite network.CookieSameSite) chromedp.Tasks {
//创建一个chrome任务
return chromedp.Tasks{
//ActionFunc是一个适配器,允许使用普通函数作为操作。
chromedp.ActionFunc(func(ctx context.Context) error {
// 设置Cookie存活时间
expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
// 添加Cookie到chrome
//SetCookie使用给定的cookie数据设置一个cookie; 如果存在,可能会覆盖等效的cookie。
err := network.SetCookie(name, value).
// 设置cookie到期时间
WithExpires(&expr).
// 设置cookie作用的站点
WithDomain(domain). //访问网站主体
// 设置httponly,防止XSS攻击
WithHTTPOnly(httpOnly).
WithSameSite(sameSite).
WithSecure(secure).
//Do根据提供的上下文执行Network.setCookie。
Do(ctx)
if err != nil {
return err
}
return nil
}),
}
}
保存cookie的其他办法
在opts中加入_<font style="color:#6272a4;">chromedp.UserDataDir("E:\\Go_workspace\\mouse-simulation\\cookie")</font>_
_,_这样浏览器将用户信息保存到一个文件夹中,下次再打开可以继承上一次的信息。加上这句话以后每次打开的浏览器就不再独立了!
获取div中的元素
这是chromedp的例子,我之前都没发现还找了好久嘤嘤嘤,这告诉我们要认真读文档。
https://github.com/chromedp/examples/blob/master/text/main.go
其实就一句话
chromedp.Text(
.Documentation-overview, &res, chromedp.NodeVisible)
鼠标拖动(滑块验证)
go使用chromedp模拟滑动验证登录 - 逍遥03 - 博客园
//模拟滑动验证
chromedp.QueryAfter("body > div.bcapc-popup.bs-popup.bcapc-popup-lang-en > div > div.bs-content > div.verify-slider.bs-slide-container > div.bs-slide-thumb", func(fctx context.Context, id runtime.ExecutionContextID, node ...*cdp.Node) error {
n := node[0]
return MouseDragNode(n, fctx)
}),
//鼠标拖拽滑块
func MouseDragNode(n *cdp.Node, cxt context.Context) error {
boxes, err := dom.GetContentQuads().WithNodeID(n.NodeID).Do(cxt)
if err != nil {
return err
}
if len(boxes) == 0 {
return chromedp.ErrInvalidDimensions
}
content := boxes[0]
c := len(content)
if c%2 != 0 || c < 1 {
return chromedp.ErrInvalidDimensions
}
var x, y float64
for i := 0; i < c; i += 2 {
x += content[i]
y += content[i+1]
}
x /= float64(c / 2)
y /= float64(c / 2)
p := &input.DispatchMouseEventParams{
Type: input.MousePressed,
X: x,
Y: y,
Button: input.Left,
ClickCount: 1,
}
// 鼠标左键按下
if err := p.Do(cxt); err != nil {
return err
}
// 拖动
p.Type = input.MouseMoved
max := 450.0
log.Println(p.X)
for {
if p.X > max {
break
}
rt := rand.Intn(20) + 20
chromedp.Run(cxt, chromedp.Sleep(time.Millisecond*time.Duration(rt)))
x := rand.Intn(2) + 15
y := rand.Intn(2)
p.X = p.X + float64(x)
p.Y = p.Y + float64(y)
if err := p.Do(cxt); err != nil {
return err
}
}
// 鼠标松开
p.Type = input.MouseReleased
return p.Do(cxt)
}
打开浏览器权限
在编写网页自动化的过程中需要开摄像头这时会有弹窗让你选择是否给权限,弹窗是无法用chromedp完成点击操作的,因此我们需要设置让浏览器自动给该网页摄像头权限,这是我找到的几个相关问题的答案:
总结一下有两种方案:
- GrantPermissions
https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-grantPermissions
GrantPermissions有两个参数(最后一个俺也不知道干啥用的)
- permissiontype有一下这些选项(由于没找到和摄像头相关的因此项目中没用这个方式)
https://chromedevtools.github.io/devtools-protocol/tot/Browser/#type-PermissionType
但是在https://github.com/chromedp/chromedp/issues/639中有人用下面的代码给权限,但是我试了没用
browser.GrantPermissions([]browser.PermissionType {
"audioCapture", "videoCapture",
}),
- WithOrigin填写弹框出现的网址,也就是会在这个网页范围内赋予权限,其他网站依旧拒绝。
browser.GrantPermissions([]browser.PermissionType{browser.PermissionTypeNotifications}).WithOrigin("https://github.com")
- SetPermission
https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-setPermission
SetPermission有三个参数,这里就拿项目中的代码为例,打开摄像头有两个权限,一个是照相,一个是麦克风
- PermissionDescriptor对应权限列表:
- SetPermission有两个参数,一个就是PermissionDescriptor,另一个有
<font style="color:#78dce8;">browser</font>._<font style="color:#9580ff;">PermissionSettingDenied</font>_
和<font style="color:#78dce8;">browser</font>._<font style="color:#9580ff;">PermissionSettingGranted</font>_
两个选项 - WithOrigin和上面一样
cameraPermission := browser.PermissionDescriptor{Name: "camera"}
microphonePermission := browser.PermissionDescriptor{Name: "microphone"}
browser.SetPermission(&cameraPermission, browser.PermissionSettingGranted).WithOrigin("https://accounts.binance.com/en/need-kyc")
browser.SetPermission(µphonePermission, browser.PermissionSettingGranted).WithOrigin("https://accounts.binance.com/en/need-kyc")
新标签页聚焦
https://github.com/chromedp/chromedp/issues/965
从network中获取内容
https://github.com/chromedp/chromedp/issues/543
已经打开的浏览器中添加页面
要添加的页面通过websock连接对应浏览器
https://github.com/chromedp/chromedp/issues/1147
https://github.com/chromedp/chromedp/issues/1013
allocCtx, cancel := chromedp.NewRemoteAllocator(context.Background(), "ws://127.0.0.1:"+info.Port+"/")
defer cancel()
已经打开的浏览器启动时监听端口–remote-debugging-port = 9222
chromedp.Flag("remote-debugging-port", info.Port),