chromedp
切换frame&iframe窗口并于元素交互
var frames []*cdp.Node
if err = chromedp.Run(ctx,
// 获取frame节点
chromedp.Nodes(`frame[name="FrameName"]`, &frames, chromedp.ByQuery),
); err != nil {
log.Fatal(err)
}
frame := frames[0]
if err = chromedp.Run(ctx,
// 通过XPath定位并点击元素
chromedp.Click(`//div[text()="文本值"]`, chromedp.BySearch, chromedp.FromNode(frame)),
); err != nil {
log.Fatal(err)
}
chromedp官方的 example 仓库并没有放出如何操作frame&iframe的代码样例,可以参阅的相关资料是 issue#72 和nav的 单元测试代码 (在TestQueryIframe函数)。
frame元素定位和操作frame里面的元素必要拆分出来分开run,放在一起,frame会提前去定位,但此时frame并没有定位成功。同理,在chromedp.Tasks也是提前定位了frame。
元素定位
- chromedp.ByQuery - CSS选择器
“p” - 获取p标签的第一个元素
“.example” - 获取class=”example”的第一个元素
“p.example” - 获取class=”example”的p标签的第一个元素
“a[target]” - 获取第一个含有target属性的a标签元素
“#div_button_excel > a” - 获取ID为div_button_excel的子标签 a
chromedp.ByQueryAll - CSS选择器,返回所有符合条件的元素
chromedp.BySearch - Xpath或者CSS selector查询, Query函数的默认查找方法
chromedp.ByID - 根据ID查询,# + ID
警告
使用 .BySearch
时, 如果查找元素是 section[class="el-container app-body"]
,
sel="section[class="app-body"]"
是行不通的,必须填入所有的class name
警告
实践中,经常发现元素定位失败,如果selenium或者js定位成功,改为调用js语句去执行动作吧。
元素取值与赋值
获取元素的text
var res string
chromedp.Run(ctx,
// 文本赋值到 `res`
chromedp.Text(`#pkg-overview`, &res, chromedp.NodeVisible, chromedp.ByID),
)
获取input元素的value
// input元素xpath路径
input := `//div[@class="wide-input el-input"]/input`
chromedp.Run(ctx,
// 文本赋值到res
chromedp.Evaluate(fmt.Sprintf(`document.evaluate('%v', document).iterateNext().value`, input), &res),
)
变更input元素的value
在selenium,习惯是先使用clear方法清空value,然后使用send_keys赋值。
在chromedp,也有Clear方法和SendKeys方法,不过Clear方法尝试过定位不了(可能对定位方法有限制), SendKeys倒没有问题。
其实还有一个SetValue方法,可以从2个步骤直接一步到位搞定。
chromedp.SetValue(`#id`, "value", chromedp.ByID),
Faq
有类似selenium WebDriverWait的等待超时设置吗?
很遗憾,没有。有一个解决办法是设置一个timeout的context,传入到Run中, 参阅 issue#647
如何变更element-ui框架时间选择器组件的值?
var res interface{}
4个步骤
更改input框的value属性
chromedp.SetValue(`input[placeholder="请选择起始时间"]`, "2021/07/15")
使用Click函数点击日期时间选择器,这一步是为了第4步运行成功
触发input事件
chromedp.Evaluate(`document.querySelector("input[placeholder='请选择结束时间']").dispatchEvent(new Event('input'))`, res),
这一步是触发了input中的v-model,修改了绑定变量的数据
触发change事件
chromedp.Evaluate(`document.querySelector("input[placeholder='请选择结束时间']").dispatchEvent(new Event('change'))`, res),
这一步执行后,时间选择器的当前选中值将显示正确
如何等待手工关闭网页后才退出程序?
在main应用程序的最后位置加上一行代码
<- ctx.Done()
这行代码在自动化完成后阻塞整个程序,直到网页被关闭
忽略NET::ERR_SSL_OBSOLETE_VERSION警告
也是增加参数 chromedp.Flag("ignore-certificate-errors", "1")