是否有可能解决网站上没有 ID 的元素?

Is there a possibility to address elements on a website which have no ID?

在 Vb.net 中,使用 Web 浏览器时,我通常使用 GetElementById 来处理例如按钮。我知道有GetElementFromPoint,我觉得特别费力

不知道ID有没有更好更简单的方法?

您将需要使用某种类型的选择器。

GetElementByID 方法效果最好,因为如果 HTML 文件格式正确,则应该只有一个元素具有该唯一 ID。

GetElementFromPoint会return一个基于文档X,Y坐标的元素,这个最好用在Document的Click事件中。

GetElementByTagName 名称将 return 元素的集合,如果您知道元素的标记类型(例如 <button>...</button><p>...</p>),则可以使用。为了帮助缩小您想要的元素的范围,您将需要遍历 returned 集合并比较元素的属性(如果您知道它们各自的值)或通过 InnerHTML 属性.

最后也是最无效的方法是 All 属性,它 return 包含文档中的每个元素。这是最不有效的原因是因为至少使用 GetElementByTagName,您可以根据标签的名称缩小集合范围。

但是,我们假设您有以下标记:

<body>
  <p>Look at my super complex HTML markup.</p>
  <button>Click Me</button>
  <button>No, click me!</button>
</body>

然后您可以使用以下内容获得显示 "Click Me" 的按钮标签:

Dim click_me As HtmlElement = WebBrowser1.Document.GetElementByTagName("button").SingleOrDefault(Function(e) e.InnerHtml = "Click Me")

看到这个问题时不时地被问到,我会看看我是否不能尝试一劳永逸地解决这个问题。下面是关于如何查找没有 ID 的元素的更详尽的指南:

- 基础知识 -

您可以使用许多 built-in 属性和方法来识别元素。最常见的包括:

  • HtmlElement.GetElementsByTagName()

    方法。 Returns document/element 中具有指定 HTML 标记的所有元素的集合。这既可以在 HtmlElement 上调用,也可以在 HtmlDocument 本身上调用。

  • HtmlElement.GetAttribute()

    方法。 Returns指定HtmlElement.

  • 上特定属性的值
  • HtmlElement.InnerHtml

    属性。 Returns 位于指定元素内的所有 HTML 代码(但不包括元素本身的代码)。

  • HtmlElement.InnerText

    属性。 Returns 位于指定元素内的所有文本(从 HTML 代码中剥离)。

  • HtmlElement.OuterHtml

    属性。 Returns 位于指定元素内的 HTML 代码,包括元素本身的代码。

这些方法和属性都可以以不同的方式用于标识元素,如下面的示例所示。

注意: 我省略了 HtmlElement.OuterText 因为它的行为有点奇怪,我不是 100% 确定它到底做了什么。


-查找没有ID的元素的例子-

以下是一组示例,说明您可以如何使用前面提到的方法和属性来找到您要查找的元素。


通过 class(-name)

查找元素

要根据其 class 属性查找元素,您必须遍历所有元素并检查每个元素的 GetAttribute("className")。如果您事先知道元素类型(标签名称),您可以通过首先使用 HtmlDocument.GetElementsByTagName() 而不是 [=37= 获取该类型 的所有元素 的集合来缩小搜索范围].

HTML code:

<div class="header">
    <div id="title" class="centerHelper">
        <img id="logo" src="img/logo.png"/>
    </div>
    <p class="headerContent">
        Hello World!
    </p>
</div>

Element to locate:

<p class="headerContent">

VB.NET code:

'Iterate all elements.
For Each Element As HtmlElement In WebBrowser1.Document.All
    If Element.GetAttribute("className") = "headerContent" Then
        'Found. Do something with 'Element'...
        Exit For 'Stop looping.
    End If
Next


根据属性查找位于另一个元素(带 ID)内的元素

为了根据其属性之一找到 child 元素,其中 child 位于 parent 元素(具有 ID)内,您只需要通过其 ID 获取 parent 元素,然后迭代其所有 children.

HTML code:

<select id="items" class="itemsList">
    <option value="2">Apple</option>
    <option value="3">Orange</option>
    <option value="5">Banana</option>
</select>

Element to locate:

<option value="5">Banana</option>

VB.NET code:

'Iterate all children of the element with ID "items".
For Each Element As HtmlElement In WebBrowser1.Document.GetElementByID("items").Children
    If Element.getAttribute("value") = "5" Then
        'Found. Do something with 'Element'...
        Exit For 'Stop looping.
    End If
Next


根据属性查找位于另一个元素(无 ID)内的元素

根据其属性之一查找 child 元素,其中 child 位于 parent 元素内(即 没有 ID)您首先必须创建一个外循环来查找 parent 元素。然后,当找到时,您可以开始迭代 children.

HTML code:

<select class="itemsList">
    <option value="2">Apple</option>
    <option value="3">Orange</option>
    <option value="5">Banana</option>
</select>

Element to locate:

<option value="5">Banana</option>

VB.NET code:

'Variable keeping track of whether we found the element we're looking for or not.
Dim ElementFound As Boolean = False

'Outer loop, looking for the parent object (<select class="itemsList">).
For Each Element As HtmlElement In WebBrowser1.Document.GetElementsByTagName("select") 'Iterate all <select> tags. You can use Document.All here as well.
    If Element.getAttribute("className") = "itemsList" Then

        'Parent found.
        'Inner loop, looking for the child element we want (<option value="5">Banana</option>).
        For Each OptionElement As HtmlElement In Element.GetElementsByTagName("option")
            If OptionElement.GetAttribute("value") = "5" Then
                'Found. Do something with 'OptionElement'...

                ElementFound = True
                Exit For 'Exit the inner loop.
            End If
        Next

        'Exit the outer loop if we found the element we're looking for.
        If ElementFound Then Exit For

    End If
Next


根据 InnerText

查找元素

在某些情况下,您要查找的元素没有任何属性,或者与网站上的许多其他元素过于相似。在这种情况下,如果其内容始终相同,您可以通过其 InnerTextInnerHtml 属性来识别它。

HTML code:

<h1>Important information</h1>
<p>Please read this information through <b>carefully</b> before continuing.</p>

<h2>Copyrighted material<h2>
<p>All material (text, images, video, etc.) on this site are <b>copyrighted</b> to COMPANY NAME.</p>

Element to locate:

<h2>Copyrighted material<h2>

VB.NET code:

For Each Element As HtmlElement In WebBrowser.Document.All
    If Element.InnerText = "Copyrighted material" Then
        'Found. Do something with 'Element'...
        Exit For 'Stop looping.
    End If
Next


根据 InnerHtml

查找元素

根据 InnerHtml 查找元素的方式与根据 InnerText 查找元素的方式完全相同,除此之外,您现在检查的字符串还包括 HTML代码。

HTML code:

<h1>Important information</h1>
<p>Please read this information through <b>carefully</b> before continuing.</p>

<h2>Copyrighted material<h2>
<p>All material (text, images, video, etc.) on this site are <b>copyrighted</b> to COMPANY NAME.</p>

Element to locate:

<p>All material (text, images, video, etc.) on this site are <b>copyrighted</b> to COMPANY NAME.</p>

VB.NET code:

'Iterate all <p> tags.
For Each Element As HtmlElement In WebBrowser.Document.GetElementsByTagName("p")
    If Element.InnerHtml.Contains("<b>copyrighted</b>") Then
        'Found. Do something with 'Element'...
        Exit For 'Stop looping.
    End If
Next