【问题标题】:Excel VBA - Web Scraping - Get value in HTML Table cellExcel VBA - Web Scraping - 在 HTML 表格单元格中获取值
【发布时间】:2020-09-04 13:55:27
【问题描述】:

我正在尝试创建一个用于抓取货物跟踪网站的宏。 但是我必须创建 4 个这样的宏,因为每家航空公司都有不同的网站。

我是 VBA 和网络抓取的新手。

我整理了一个适用于 1 个网站的代码。但是当我试图将它复制到另一个时,我陷入了困境。我想这可能是我指代元素的方式,但就像我说的,我是 VBA 新手,对 HTML 一无所知。

我正在尝试从图像中的突出显示行中获取“通知”值。

IMAGE:"notified" text to be extracted 下面是我到目前为止编写的代码,它卡在了循环中。 对此的任何帮助将不胜感激。

Sub FlightStat_AF()

Dim url As String
Dim ie As Object
Dim nodeTable As Object

  'You can handle the parameters id and pfx in a loop to scrape dynamic numbers
  url = "https://www.afklcargo.com/mycargo/shipment/detail/057-92366691"

  'Initialize Internet Explorer, set visibility,
  'call URL and wait until page is fully loaded
  Set ie = CreateObject("InternetExplorer.Application")
  ie.Visible = False
  ie.navigate url
  Do Until ie.readyState = 4: DoEvents: Loop
  
  'Wait to load dynamic content after IE reports it's ready
  'We can do that in a loop to match the point the information is available
  Do
    On Error Resume Next
    Set nodeTable = ie.document.getElementByClassName("block-whisper")
    On Error GoTo 0
  Loop Until Not nodeTable Is Nothing
  
  'Get the status from the table
  MsgBox Trim(nodeTable.getElementsByClassName("fs-12 body-font-bold").innerText)
  
  'Clean up
  ie.Quit
  Set ie = Nothing
  Set nodeTable = Nothing
End Sub

【问题讨论】:

  • 您很可能陷入了一个循环,因为永远找不到“block-whisper”。在这种情况下,您的代码将永远循环。循环并不是真正需要的。您可以找到该元素,也可以不找到,您可以采取任何一种方式。
  • @BrianMStafford,需要循环,因为它是在加载源页面后加载的动态表。在元素部分,我不确定我是否指的是正确的元素,因为我对 HTML 一无所知。你能看看附上的图片,看看我犯了什么错误吗?
  • 你尝试我的代码从这个答案到另一个页面:stackoverflow.com/questions/63738093/… 那行不通。每个页面的抓取代码都不同,因为每个页面都不同。我现在没有时间看看它在这个页面上是如何工作的。也许以后。
  • 试试this link。你可以使用 xhr 来获取你想要的。
  • @SIM,谢谢。但我对网络抓取完全陌生,只有基本的 VBA 知识。你能帮我写代码吗?

标签: excel vba web-scraping


【解决方案1】:

一些基础知识:
对于像现在这样的简单访问,您可以使用 DOM(文档对象模型)的 get 方法。但是getElementByID()getElementsByClassName()/getElementsByTagName()之间有一个重要的区别。

getElementByID() 搜索 html 标记的唯一 ID。这被写为 html 标签的 ID 属性。如果页面保持 html 标准,则只有一个元素具有此唯一 ID。这就是方法以getElement开头的原因。

如果在使用该方法时未找到 ID,VBA 将引发运行时错误。因此,调用被封装在我的另一个答案的循环中,关闭并再次打开错误处理。但是在这个问题的页面中,有问题的 html 区域没有 ID。

相反,可以直接访问所需的元素。您尝试使用getElementsByClassName() 进行访问。这是正确的。但这里与getElementByID() 不同。

getElementsByClassName()getElementsByTagName()getElements 开头。那是复数,因为可以有尽可能多的具有相同类或标签名称的元素。这两种方法都创建了一个 html 节点集合。所有具有所要求的类或标签名称的 html 元素都将在这些集合中列出。

所有元素都有一个索引,就像一个数组。索引从 0 开始。要访问特定元素,必须指定所需的索引。两个类名fs-12 body-font-bold(类名用空格分隔,也可以只用一个类名构建一个节点集合)给节点集合传递2个html元素。你想要第二个,所以你必须使用索引 1。

这是使用 IE 的询问页面的 VBA 代码:

Sub FlightStat_AF()

Dim url As String
Dim ie As Object

  'You can handle the parameters id and pfx in a loop to scrape dynamic numbers
  url = "https://www.afklcargo.com/mycargo/shipment/detail/057-92366691"

  'Initialize Internet Explorer, set visibility,
  'call URL and wait until page is fully loaded
  Set ie = CreateObject("InternetExplorer.Application")
  ie.Visible = False
  ie.navigate url
  Do Until ie.readyState = 4: DoEvents: Loop
  
  'Wait to load dynamic content after IE reports it's ready
  'We do that with a fix manual break of a few seconds
  'because the whole page will be "reload"
  'The last three values are hours, minutes, seconds
  Application.Wait (Now + TimeSerial(0, 0, 3))
  
  'Get the status from the table
  MsgBox Trim(ie.document.getElementsByClassName("fs-12 body-font-bold")(1).innerText)
  
  'Clean up
  ie.Quit
  Set ie = Nothing
End Sub

编辑:子函数

这个子来测试功能:

Sub testFunction()
  Dim flightStatAfResult As String
  flightStatAfResult = FlightStat_AF("057-92366691")
  MsgBox flightStatAfResult
End Sub

这是子函数:

Function FlightStat_AF(cargoNo As String) As String

Dim url As String
Dim ie As Object
Dim result As String

  'You can handle the parameters id and pfx in a loop to scrape dynamic numbers
  url = "https://www.afklcargo.com/mycargo/shipment/detail/" & cargoNo

  'Initialize Internet Explorer, set visibility,
  'call URL and wait until page is fully loaded
  Set ie = CreateObject("InternetExplorer.Application")
  ie.Visible = False
  ie.navigate url
  Do Until ie.readyState = 4: DoEvents: Loop
  
  'Wait to load dynamic content after IE reports it's ready
  'We do that with a fix manual break of a few seconds
  'because the whole page will be "reload"
  'The last three values are hours, minutes, seconds
  Application.Wait (Now + TimeSerial(0, 0, 3))
  
  'Get the status from the table
  result = Trim(ie.document.getElementsByClassName("fs-12 body-font-bold")(1).innerText)
  
  'Clean up
  ie.Quit
  Set ie = Nothing
  
  'Return value of the function
  FlightStat_AF = result
End Function

【讨论】:

  • 感谢您提供此代码!我正在为另一个货物跟踪网站编写类似的代码。我已经导航到页面。但问题是数据表在 IE 中根本不加载。它在 chrome 上完美加载。你知道背后的原因吗?这是我试图从中抓取的网站 - trackingmore.com/aircargo/72403698656
  • @AchalAesai 加载页面动态内容的技术对于 IE 来说太现代了。 IE 已经有一段时间没有进一步开发,现代 JavaScript 无法再执行。我想如果你使用像 Selenium 这样的接口,你只能抓取所需的数据。使用 Selenium,可以从 VBA 控制 IE 以外的浏览器。 selenium.dev 另一种可能性是使用另一种语言,如 Python,带有适当的库,如 Beautifull Soap。
  • 感谢您澄清这一点。我对python一无所知。但我会按照你的建议研究硒。
  • 我正在尝试将上述代码创建为函数。当我将它作为子程序运行时,它会给我正确的结果。但是当我将它作为函数运行时,它会给我一个#Value 错误。我哪里错了?下面是我为将 sub 转换为函数而编写的预兆。
  • 感谢您的代码。我用 test sub 试了一下,msgbox 给出了正确的答案。但是当我将它作为函数=FlightStat_AF(H3) 运行时,它再次给我一个#value 错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 1970-01-01
  • 2023-02-08
  • 2016-06-29
相关资源
最近更新 更多