vba - 在 HTMLElement 上使用 getElementById 而不是 HTMLDocument

标签 vba web-scraping

我一直在使用 VBS/VBA 从网页中抓取数据。

如果它是 Javascript,我会很容易离开,但它在 VBS/VBA 中似乎并不那么简单。

这是我为回答而制作的示例,它有效,但我计划使用 getElementByTagName 访问子节点但我不知道如何使用它们! HTMLElement对象没有这些方法。

Sub Scrape()
Dim Browser As InternetExplorer
Dim Document As HTMLDocument
Dim Elements As IHTMLElementCollection
Dim Element As IHTMLElement

Set Browser = New InternetExplorer

Browser.navigate "http://www.hsbc.com/about-hsbc/leadership"

Do While Browser.Busy And Not Browser.readyState = READYSTATE_COMPLETE
    DoEvents
Loop

Set Document = Browser.Document

Set Elements = Document.getElementsByClassName("profile-col1")

For Each Element in Elements
    Debug.Print "[  name] " & Trim(Element.Children(1).Children(0).innerText)
    Debug.Print "[ title] " & Trim(Element.Children(1).Children(1).innerText)
Next Element

Set Document = Nothing
Set Browser = Nothing
End Sub

我一直在看HTMLElement.document属性,看看它是否像文档的片段,但它要么难以使用,要么不是我认为的
Dim Fragment As HTMLDocument
Set Element = Document.getElementById("example") ' This works
Set Fragment = Element.document ' This doesn't

这似乎也是一种冗长的方法(尽管这通常是 vba imo 的方法)。
任何人都知道是否有更简单的方法来链接函数?
Document.getElementById("target").getElementsByTagName("tr")会很棒...

最佳答案

我也不喜欢。

所以使用javascript:

Public Function GetJavaScriptResult(doc as HTMLDocument, jsString As String) As String

    Dim el As IHTMLElement
    Dim nd As HTMLDOMTextNode

    Set el = doc.createElement("INPUT")
    Do
        el.ID = GenerateRandomAlphaString(100)
    Loop Until Document.getElementById(el.ID) Is Nothing
    el.Style.display = "none"
    Set nd = Document.appendChild(el)

    doc.parentWindow.ExecScript "document.getElementById('" & el.ID & "').value = " & jsString

    GetJavaScriptResult = Document.getElementById(el.ID).Value

    Document.removeChild nd

End Function


Function GenerateRandomAlphaString(Length As Long) As String

    Dim i As Long
    Dim Result As String

    Randomize Timer

    For i = 1 To Length
        Result = Result & Chr(Int(Rnd(Timer) * 26 + 65 + Round(Rnd(Timer)) * 32))
    Next i

    GenerateRandomAlphaString = Result

End Function

如果您对此有任何问题,请告诉我;我已将上下文从方法更改为函数。

顺便问一下,你用的是什么版本的IE?我怀疑您使用的是 < IE8。如果您升级到 IE8,我认为它会将 shdocvw.dll 更新为 ieframe.dll,您将能够使用 document.querySelector/All。

编辑

评论回复,这不是真正的评论:
基本上,在 VBA 中执行此操作的方法是遍历子节点。问题是你没有得到正确的返回类型。您可以通过创建自己的类(分别)实现 IHTMLElement 和 IHTMLElementCollection 来解决此问题;但这对我来说太痛苦了而没有得到报酬:)。如果您下定决心,请阅读 VB6/VBA 的实现关键字。
Public Function getSubElementsByTagName(el As IHTMLElement, tagname As String) As Collection

    Dim descendants As New Collection
    Dim results As New Collection
    Dim i As Long

    getDescendants el, descendants

    For i = 1 To descendants.Count
        If descendants(i).tagname = tagname Then
            results.Add descendants(i)
        End If
    Next i

    getSubElementsByTagName = results

End Function

Public Function getDescendants(nd As IHTMLElement, ByRef descendants As Collection)
    Dim i As Long
    descendants.Add nd
    For i = 1 To nd.Children.Length
        getDescendants nd.Children.Item(i), descendants
    Next i
End Function

关于vba - 在 HTMLElement 上使用 getElementById 而不是 HTMLDocument,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15191847/

相关文章:

vba - 首次运行时出现 OnAction 运行时错误 "1004"

web-scraping - 使用 JSoup 抓取电子邮件和链接

java - Java 中 WebDriver/ChromeDriver 所需的依赖项

python - 脚本无法解析重定向网址中的标题

html - 从html中的脚本获取javascript对象

excel - 动态 Excel VBA 代码更改文本框大小

sql - 详细的 QueryTables 错误处理

vba - 使用动态引用将 Excel 公式转换为 VBA 代码

ms-access - Access 中 Left() 和 Left$() 函数的区别

python - 抓取 html 表 - python