选择器

原文:https://go-rod.github.io/i18n/zh-CN/#/selectors/README

收录该文档时间: 2024-11-21T08:07:59+08:00

选择器

​ Rod 提供了很多获取元素的方法。 它们的名称都以 MustElementElement 作为前缀。 如果你在 IDE 中键入 Element,你会看到如下所有可用的选择器:

ide-selectors

​ 如果你将光标停留在方法上,你会看到如下的文档:

ide-doc

​ 通常来说你只需要一些 CSS 选择器 的基础知识就可以完成你想要完成的自动化任务。 在本文档中,我们将只使用 CSS 选择器从页面中获取元素。

通过文本内容

​ 使用 ElementR ,通过文本内容来匹配元素。 例如选择下图中的搜索输入框:

match-text

1
2
page.MustElementR("input", "Search or jump")
page.MustElementR("input", "/click/i") // 使用大小写不敏感标志 "i"

​ 因为使用了 js regex, 所以我们不需要匹配文本的整个上下文。 要匹配的文本是在网站上实际看到的,而不是源代码。 试比较下图中的 1 和 2。 你可以使用 Devtools 的 copy 帮助函数将文本复制到剪贴板(见 4):

copy-text

通过 XPath

​ 我们推荐使用 CSS 选择器来选择元素(比如你不能用 XPath 来选择渲染的文本)。 但对于使用其他语言的程序员来说,可能有时 XPath 来得更方便。 使用 ElementX 来根据 XPath 匹配:

1
page.MustElementX("//h2")

通过 JavaScript

​ 如果你的查询很复杂,或者如果你想使用一个类似于 jQuery 的高级查询引擎:

1
page.MustElementByJS(`() => jQuery('option:selected')[0]`)

如果你看一下其他选择器(比如 ElementElementR)的源码,你会发现他们实际上都基于 ElementByJS,而 ElementByJS 则基于 Page.Evaluate。 有关如何运行 js 代码,见 JavaScript 运行时。 通常会使用 ElementByJS 自行创建选择器来扩展 Rod。

选择多个元素

​ 获取多个元素的方法的名称都以 MustElementsElements 作为前缀。 单元素选择器和多元素选择器之间的一个关键区别是,单元素选择器会等待元素出现。 如果一个多元素选择器没有找到任何东西,他会立即返回一个空列表。

遍历元素树

​ 还有一些方便的选择器用于选择元素内部或周围的元素,如 MustParentMustNextMustPrevious等。

​ 下面是一个使用多个选择器从页面中获取内容的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 在 awesome-go 页面上,找出指定的区域 sect,
// 并从页面获取相关项目。
func main() {
    page := rod.New().MustConnect().MustPage("https://github.com/avelino/awesome-go")

    section := page.MustElementR("p", "Selenium and browser control tools").MustNext()

    // 获取一个元素的子元素
    projects := section.MustElements("li")

    for _, project := range projects {
        link := project.MustElement("a")
        log.Printf(
            "project %s (%s): '%s'",
            link.MustText(),
            link.MustProperty("href"),
            project.MustText(),
        )
    }
}

从 iframe 中获取元素

​ 例如,从如下的多层嵌套的 iframe 中选择按钮:

iframes

​ 代码看起来是这样的:

1
2
3
frame01 := page.MustElement("iframe").MustFrame()
frame02 := frame01.MustElement("iframe").MustFrame()
frame02.MustElement("button")

搜索元素

​ 还有另一个强大的帮助函数可以获取元素,那就是 MustSearch。 它不如上面提到的选择器精确,但是如果你想从深层嵌套的 iframe 或 shadow dom 中获取元素,使用它就会很方便。

​ 这一功能和 Devtools 中的 Search for nodes 是一样的。 你可以使用 Devtools 的这一功能来调试出用什么关键字来选择你想要的元素,如下图所示:

search

​ 要选择和 从 iframe 中获取元素 中一样的元素,我们可以这样:

1
page.MustSearch("button")

竞争选择器

​ Rod 鼓励无 sleep 的自动化任务,这样可以增加任务的可靠性。 当一个操作有多种可能的结果时,我们不使用 sleep 来等待页面跳转或加载完毕。 例如,登录网页时密码可能错误,这时我们希望分别处理成功和失败的情况。 我们应该避免这样的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    page := rod.New().MustConnect().MustPage("https://leetcode.com/accounts/login/")

    page.MustElement("#id_login").MustInput("username")
    page.MustElement("#id_password").MustInput("password").MustType(input.Enter)

    time.Sleep(10 * time.Second) // Please avoid the use of time.Sleep!

    if page.MustHas(".nav-user-icon-base") {
        // 在成功登陆后打印用户名
        fmt.Println(page.MustElement(".nav-user-icon-base").MustAttribute("title"))
    } else if page.MustHas("[data-cy=sign-in-error]") {
        // 当用户名或密码错误
        fmt.Println(page.MustElement("[data-cy=sign-in-error]").MustText())
    }
}

​ 相反,我们应该这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func main() {
    page := rod.New().MustConnect().MustPage("https://leetcode.com/accounts/login/")

    page.MustElement("#id_login").MustInput("username")
    page.MustElement("#id_password").MustInput("password").MustType(input.Enter)

    // 轮询,直到匹配到一个选择器
    page.Race().Element(".nav-user-icon-base").MustHandle(func(e *rod.Element) {
        // 在成功登陆后打印用户名
        fmt.Println(e.MustAttribute("title"))
    }).Element("[data-cy=sign-in-error]").MustHandle(func(e *rod.Element) {
        // 当用户名或密码错误
        panic(e.MustText())
    }).MustDo()
}
最后修改 November 21, 2024: init (2a1db69)