【问题标题】:VBA Excel ScrapingVBA Excel 抓取
【发布时间】:2014-12-22 06:55:09
【问题描述】:

我开始尝试学习抓取。我得到了这个登录后的页面,我记得读过你不应该在通过标记名获取元素之后尝试做 (1)、(2) 或 (3) 的事情。但是你应该得到一些更独特的东西,比如类名或 ID。但是谁能告诉我为什么

GetTag 工作

Dim Companyname As String
Companyname = ie.document.getElementsByTagName("span")(1).innertext

此 GetClass 不起作用

Dim Companyname As String
Companyname = ie.document.getElementsByClassName("account-website-name").innertext

这是我正在抓取的文本

<span class="account-website-name" data-journey-name="true">Dwellington Journey</span>

【问题讨论】:

  • 每当您使用可能获得比单个元素更多的东西时,您都需要提供序数索引。您在第一个示例中使用 (1) 执行此操作,该 (1) 引用第二个 &lt;span&gt; 元素(序数从零开始)。在第二个示例中,您省略了序数,因此 .getElementsByClassName 不知道返回哪个,即使只有一个匹配。
  • 你是个老板!谢谢!
  • @Jeeped 这听起来更像是一个答案而不是评论,如何充实它,将其作为一个发布并获得您似乎应得的代表?
  • 谢谢@Aiken - 我刚刚去meta阅读this并尝试决定行动方案。似乎以答案社区 Wiki 的身份重新提交是首选处理方式。
  • @Jeeped 我不明白为什么它必须是一个社区维基,你发布的评论结果是一个答案,为什么会失去你的代表?作为社区 wiki 发布是指其他人在 cmets 中回答但尚未发布实际答案。

标签: html excel vba web-scraping


【解决方案1】:

按属性获取ELEMENTS与按属性获取ELEMENTS

主要有两种不同类型的命令可以从网页的.Document 中检索一个或多个元素;返回单个对象的对象和返回对象集合的对象。

获取元素

当使用getElementById 时,您要求的是单个对象(例如MSHTML.IHTMLElement)。在这种情况下,可以直接检索属性(例如.Value.innerText.outerHtml 等)。 HTML 正文中不应有多个唯一的 id 属性,因此此函数应该安全地返回 i.e.document 中唯一匹配的元素。

'typical VBA use of getElementById
Dim CompanyName As String
CompanyName = ie.document.getElementById("CompanyID").innerText

警告:我注意到越来越多的网页设计师似乎认为对多个元素使用相同的 id 是 oh-key-doh-key,只要 id 位于不同的父元素中,例如不同的 @ 987654330@ 元素。 AFAIK,这显然是错误的,但似乎是一种日益增长的做法。注意使用.getElementById时返回的内容。

获取元素

当使用 getElementsByTagNamegetElementsByClassName 等词时,Elements 是复数形式,您将返回对象的 集合(例如 MSHTML.IHTMLElementCollection),即使该集合仅包含一个或什至没有。如果您想使用它们直接访问集合中某个元素的属性,则必须提供 序数索引 编号,以便引用集合中的单个元素。这些集合中的索引号从零开始(即第一个从 (0) 开始)。

'retrieve the text from the third <span> element on a webpage
Dim CompanyName As String
CompanyName = ie.document.getElementsByTagName("span")(2).innerText

'output all <span> classnames to the Immediate window until the right one comes along
'retrieve the text from the first <span> element with a classname of 'account-website-name'
Dim e as long, es as long
es = ie.document.getElementsByTagName("span").Length - 1
For e = 0 To es
    Debug.Print ie.document.getElementsByTagName("span")(e).className
    If ie.document.getElementsByTagName("span")(e).className = "account-website-name" Then
        CompanyName = ie.document.getElementsByTagName("span")(e).innerText
        Exit For
    End If
Next e

'same thing, different method
Dim eSPN as MSHTML.IHTMLElement, ecSPNs as MSHTML.IHTMLElementCollection
ecSPNs = ie.document.getElementsByTagName("span")
For Each eSPN in ecSPNs
    Debug.Print eSPN.className
    If eSPN.className = "account-website-name" Then
        CompanyName = eSPN.innerText
        Exit For
    End If
Next eSPN 
Set eSPN = Nothing: Set ecSPNs = Nothing

总而言之,如果您的 Internet.Explorer 方法使用 Elements(复数)而不是 Element(单数),那么您将返回一个必须附加索引号的集合如果您希望将集合中的某个元素视为单个元素。

【讨论】:

  • 而且……这真是令人印象深刻。谢啦!我同意,感觉同一个 ID 的东西像野火一样蔓延开来。在此之后,我实际上得到了 4 个具有相同 ID 和类名但在不同父母名下的不同号码。弄清楚了所有这些。但再次感谢你。一个 S 就有很大的不同。
【解决方案2】:

CSS 选择器:

您可以使用 .account-website-name 的 CSS 选择器实现相同的目的

"." 表示类名。如果有多个匹配元素,这将返回一组匹配元素。


CSS 查询:


VBA:

您使用.document.querySelectorAll 方法应用选择器。这将返回一个 nodeList,您将遍历它的 .Length,按索引访问项目,从 0 开始。

Dim aNodeList As Object, i As Long
Set aNodeList = ie.document.querySelectorAll(".account-website-name")

For i = 0 To aNodeList.Length -1
    Debug.Print aNodeList.Item(i).innerText
    ' Debug.Print aNodeList(i).innerText ''<== sometimes this syntax instead
Next

【讨论】:

    猜你喜欢
    • 2014-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    相关资源
    最近更新 更多