VBA/DOM - 根据属性获取元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40282180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-12 11:25:36  来源:igfitidea点击:

VBA/DOM - Get elements based on attribute

vbaexcel-vbadomexcel

提问by Vegard

Excel 2013 on Windows 7. XPath/Javascript/jQueryis out of scope.

Excel中2013在Windows 7 XPath/ Javascript/jQuery是的范围了。

I am trying to iterate over select divelements in a page, namely elements that have a specific data-levelattribute.

我试图迭代div页面中的选择元素,即具有特定data-level属性的元素。

My current approach is similar to this, but I was unable to find a non-manual way to select elements based on attributes. The closest I came was something like:

我目前的方法与此类似,但我无法找到一种基于属性选择元素的非手动方法。我最接近的是这样的:

With CreateObject("WINHTTP.WinHTTPRequest.5.1")
    .Open "GET", url, False
    .Send
    pHTML.body.innerHTML = .ResponseText
End With

Set eCollection = pHTML.getElementsByClassName("chapter").getElementsByTagName("div")

For i = 0 To eCollection.Length
    If eCollection(i).getAttribute("data-level") >= 0 Then ' Throw cake
Next i

This solution, while I am sure it is viable (if unelegant), seems sub-optimal if only for how big the loop is going to end up being when I start looking for specific elements and sequences of elements within these elements.

这个解决方案,虽然我确信它是可行的(如果不优雅),但如果仅当我开始寻找特定元素和这些元素中的元素序列时循环最终会有多大,它似乎是次优的。

So I am looking for a way to do something like this:

所以我正在寻找一种方法来做这样的事情:

For Each pElement In pHTML.getElementsByClassName("chapter").getElementsByTagName("div").getElementsByAttribute("data-level")
    ' Throw cake at the element
Next

I'm aware that there is no method getElementsByAttribute, hence the question.
Is there some approach here that I am blind to, or am I locked to manual iteration?

我知道没有方法getElementsByAttribute,因此问题。
这里有什么方法是我看不到的,还是我被锁定在手动迭代中?

Alternatively, if I swap my current approach for creating an IE instance, á la this answer, could I concievably use querySelectorAllto end up with something resembling the result I have outlined above?

或者,如果我交换我当前创建 IE 实例的方法,就像这个答案一样,我是否可以使用querySelectorAll最终得到与我上面概述的结果类似的东西?

回答by Vegard

For anyone else coming this way, the outer shell, so to speak, can look like this:

对于其他人来说,可以这么说,外壳可以是这样的:

Sub ScrapeWithHTMLObj(url As String, domClassName As String, domTag As String, domAttribute As String, domAttributeValue As String)
    ' Dependencies:
    ' * Microsoft HTML Object Library

    ' Declare vars
    Dim pHTML As HTMLDocument
    Dim pElements As Object, pElement As Object

    Set pHTML = New HTMLDocument

    ' Basic URL healthcheck
    Do While (url = "" Or (Left(url, 7) <> "http://" And Left(url, 8) <> "https://"))
        MsgBox ("Invalid URL!")
        url = InputBox("Enter new URL: (0 to terminate)")
        If url = "0" Then Exit Sub
    Loop

    ' Fetch page at URL
    With CreateObject("WINHTTP.WinHTTPRequest.5.1")
        .Open "GET", url, False
        .Send
        pHTML.body.innerHTML = .ResponseText
    End With

    ' Declare page elements
    Set pElements = pHTML.getElementsByClassName(domClassName)
    Set pElement = pElements(0).getElementsByTagName(domTag)

    ' Extract only elements with wanted attribute
    pEleArray = getElementsByAttribute(pElement, domAttribute, domAttributeValue)

    For Each e In pEleArray
        ' Do stuff to elements
        Debug.Print e.getAttribute(domAttribute)
    Next
End Sub

If you go this route, you'll also need something like this:

如果你走这条路,你还需要这样的东西:

Function getElementsByAttribute(pObj As Object, domAttribute As String, domAttributeValue As String) As Object()
    Dim oTemp() As Object
    ReDim oTemp(1 To 1)

    For i = 0 To pObj.Length - 1
        'Debug.Print pObj(i).getAttribute(domAttribute)
        If pObj(i).getAttribute(domAttribute) = domAttributeValue Then
            Set oTemp(UBound(oTemp)) = pObj(i)
            ReDim Preserve oTemp(1 To UBound(oTemp) + 1)
        End If
    Next i

    ReDim Preserve oTemp(1 To UBound(oTemp) - 1)

    getElementsByAttribute = oTemp
End Function

Depending on the HTML tree, you'll need to change which elements you zero in on in the sub, obviously. For the site I used in testing, this structure worked flawlessly.

显然,根据 HTML 树,您需要更改在子中归零的元素。对于我在测试中使用的站点,这种结构完美无缺。

Example usage:
Call ScrapeWithHTMLObj("https://somesite", "chapter-index", "div", "data-level", "1")

用法示例:
Call ScrapeWithHTMLObj("https://somesite", "chapter-index", "div", "data-level", "1")

It will enter the first class named chapter-index, select all elements with the divtag, and finally extract all elements containing the attribute data-levelwith value 1.

它将进入第一个名为 的类chapter-index,选择所有带有div标记的元素,最后提取所有包含属性data-level值为 的元素1