chromedp

github:

https://github.com/chromedp/chromedp

知乎:

https://zhuanlan.zhihu.com/p/515734676

切换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个步骤

  1. 更改input框的value属性

chromedp.SetValue(`input[placeholder="请选择起始时间"]`, "2021/07/15")

  1. 使用Click函数点击日期时间选择器,这一步是为了第4步运行成功

  2. 触发input事件

chromedp.Evaluate(`document.querySelector("input[placeholder='请选择结束时间']").dispatchEvent(new Event('input'))`, res),

这一步是触发了input中的v-model,修改了绑定变量的数据

  1. 触发change事件

chromedp.Evaluate(`document.querySelector("input[placeholder='请选择结束时间']").dispatchEvent(new Event('change'))`, res),

这一步执行后,时间选择器的当前选中值将显示正确

如何等待手工关闭网页后才退出程序?

在main应用程序的最后位置加上一行代码

<- ctx.Done()

这行代码在自动化完成后阻塞整个程序,直到网页被关闭

忽略ERR_CERT_AUTHORITY_INVALID警告

增加参数 chromedp.Flag("ignore-certificate-errors", "1")

opts := append(
    chromedp.DefaultExecAllocatorOptions[:],
    chromedp.Flag("ignore-certificate-errors", "1"),
)

参考自 https://github.com/chromedp/chromedp/issues/157

忽略NET::ERR_SSL_OBSOLETE_VERSION警告

也是增加参数 chromedp.Flag("ignore-certificate-errors", "1")

设置cookies

问题: https://www.zhihu.com/question/267059966/answer/2750560795