【问题标题】:Load all of Dynamically Loading HTMLTable - VBA加载所有动态加载 HTMLTable - VBA
【发布时间】:2021-10-24 00:07:49
【问题描述】:

我有用于加载 HTMLTable 的代码,但我最近有一个很大的列表,并意识到它只是拉到列表的顶部。当我在浏览器中向下滚动表格时,观察开发控制台的进一步调查显示多个“发布”请求。我正在讨论构建代码(如果可以的话)以尝试找到表中的最后一项,然后再次运行查询,但我想看看我是否可以“正确”解决根本问题而不是破解它。

我怎样才能模拟滚动和监控帖子请求或任何其他建议?

这是一些示例代码,但不幸的是,我不能将链接共享为仅作为 LAN 访问。注意:不需要登录,但如果不使用 IE 对象来生成与请求相关的 cookie(无法通过 CLI 发布),我无法弄清楚如何做到这一点。

 Do Until InStr(1, IEObj.document.getElementById("gbox_tbl").innerHTML, "WAREHOUSE") > 0
   DoEvents
 Loop
 Dim table As MSHTML.HTMLTable, HTMLCollection As IHTMLElementCollection
 Set table = IEObj.document.getElementById("gbox_tbl")
  
 Set ClipBoard = New MSForms.DataObject
 Application.Wait (Now() + TimeValue("00:00:01"))
 ClipBoard.SetText table.outerHTML
 ClipBoard.PutInClipboard
 
 Dim TempWS As Worksheet
 Call WorksheetCreateDelIfExists("TempSheet")
 Set TempWS = Worksheets("TempSheet")
 TempWS.Activate
 Range("A1").Select
 ActiveSheet.Paste
 'Stop
 Dim UsedRng As Range
 Set UsedRng = GetUsedRange(TempWS)
 UsedRng.Copy

 Dim FindSMPDestWS As Worksheet, wss As Worksheet, SearchTerm As String, i As Integer
 i = 0
 SearchTerm = "FindWSR"
 For Each wss In ActiveWorkbook.Worksheets
  If Left(wss.Name, Len(SearchTerm)) = SearchTerm Then
   i = i + 1
  End If
 Next wss
 If i = 0 Then
  Call WorksheetCreate("FindWSR")
 Else
  Call WorksheetCreate("FindWSR(" & i & ")")
 End If
 Set FindSMPDestWS = ActiveSheet
 FindSMPDestWS.Activate
 Range("A1").Select
 FindSMPDestWS.Paste
 If Range("A1") <> "Loading..." Then
  Application.Wait (Now() + TimeValue("00:00:01"))
  ClipBoard.SetText table.outerHTML
  ClipBoard.PutInClipboard
  Range("A1").Select
  FindSMPDestWS.Paste
 End If

【问题讨论】:

  • 您检查过帖子请求吗?您需要了解 POST 请求在做什么。由于我们没有看到这些,因此很难提供建议。
  • 例如POST 请求可能针对成批的结果,并且在其中一个/多个结果中,您可能有总计数和批次大小/偏移量/页码等,根据这些数据,您可能能够制定逻辑来发布您自己的 POST请求获取所有数据。
  • 两种 IE 典型方法是:1)在页面底部找到一个元素并滚动到它 2)保持滚动窗口高度并获取元素计数,直到不改变。这取决于能够访问滚动元素。要搜索的 SO 示例通常涉及 lazy-loading。您使用哪个取决于哪个可以提供可靠的结果。如果使用 ajax 进行更新,一种不太常见的方法是使用 execScript 来监视 ajax 的完成情况。就个人而言,我会选择 POST 请求而不是 IE,但我知道这可能是不可能的。
  • couldn't post via CLI ?不知道你是怎么做的。您也许可以使用 CURL 执行所有这些操作。

标签: excel vba internet-explorer html-table


【解决方案1】:

更新:我遇到了另一个表,我下面的 Sub 没有正常工作,所以我想再次解决这个问题,以找到更强大的解决方案。 @Qharr 关于术语“延迟加载”网页的提示与他评论中的 URL 一起提供了帮助。以下是我所拥有的,它适用于我测试的两张表,但它们都是同一家公司编写的内部页面,所以 YMMV 但我很高兴一如既往地接受建议/反馈。

代码:

Sub Testing()
 'Scroll Entire HTML Table
 Dim ScrollBarDivInt As Integer, StepLng As Long, ScrollElmIDStr As String, LoadingElmIDStr As String, LoadingTrueCheckStr As String, LoadingFalseCheckStr As String
 ScrollBarDivInt = 0
 StepLng = 1000
 ScrollElmIDStr = "ui-jqgrid-bdiv"
 LoadingElmIDStr = "load_grdDisposition"
 LoadingTrueCheckStr = "block"
 LoadingFalseCheckStr = "none"
 Call Scroll_HTMLTable(ScrollBarDivInt, StepLng, ScrollElmIDStr, LoadingElmIDStr, LoadingTrueCheckStr, LoadingFalseCheckStr)
End Sub

Public Sub Scroll_HTMLTable(ByVal ScrollBarDivInt As Integer, ByVal StepLng As Long, ByVal ScrollElmIDStr As String, ByVal LoadingElmIDStr As String, ByVal LoadingTrueCheckStr As String, ByVal LoadingFalseCheckStr As String)
 Dim HLng As Long
 HLng = IEObj.document.getElementsByClassName(ScrollElmIDStr)(ScrollBarDivInt).ScrollHeight
 For i = 1 To HLng Step StepLng
  IEObj.document.getElementsByClassName(ScrollElmIDStr)(ScrollBarDivInt).ScrollTop = i
  Application.Wait (Now() + TimeValue("00:00:1"))
  If InStr(IEObj.document.getElementById(LoadingElmIDStr).outerHTML, LoadingTrueCheckStr) > 0 Then UILoading_Bool = True
  If InStr(IEObj.document.getElementById(LoadingElmIDStr).outerHTML, LoadingFalseCheckStr) > 0 Then UILoading_Bool = False
  Debug.Print "UILoading_Bool = " & UILoading_Bool
  Do While UILoading_Bool = True
   Application.Wait (Now() + TimeValue("00:00:1"))
   If InStr(IEObj.document.getElementById(LoadingElmIDStr).outerHTML, LoadingTrueCheckStr) > 0 Then UILoading_Bool = True
   If InStr(IEObj.document.getElementById(LoadingElmIDStr).outerHTML, LoadingFalseCheckStr) > 0 Then UILoading_Bool = False
  Loop
 Next
End Sub

注意:我可以使用下面的内容直接滚动到底部,但是我的网页真的很懒,除非我在滚动时暂停,否则它不会加载表格的“中间”,因此是“等待”。

IEObj.document.getElementsByClassName(ScrollElmIDStr)(ScrollBarDivInt).ScrollTop = IEObj.document.getElementsByClassName(ScrollElmIDStr)(ScrollBarDivInt).ScrollHeight

结束更新


这并不完全干净,但它现在确实有效,不幸的是,在重新设置表格以检查长度之前,我似乎无法找到一种方法来“检查”页面是否已加载。我正在使用“application.wait”,它在我的测试中运行良好,但我稍后会尝试改进循环。我也愿意就更好的方法来解决这个问题提出建议。

Public Sub ScrollTable(table As MSHTML.HTMLTable)
 Dim tcell As Object, tcells As Object, ltablerow As Long, c As Long
  Set tcells = table.getElementsByTagName("tr")
  Do
  c = 0
  ltablerow = tcells.Length
  'Stop
  For Each tcell In tcells
  c = c + 1
   If c > ltablerow - 5 Then
    tcell.Click
    tcell.Focus
    SendKeys "{DOWN}"
    SendKeys "{DOWN}"
   End If
  Next
  Application.Wait (Now() + TimeValue("00:00:05"))
  Set tcells = table.getElementsByTagName("tr")
  Loop Until tcells.Length = ltablerow

End Sub

【讨论】:

  • 感谢您发布此问题的解决方案。当您可以标记时,您可以将答案标记为已接受的答案。它可以在未来帮助其他社区成员解决类似的问题。感谢您的理解。
  • 我会考虑获得很棒的免费rubberduck add-in 并使用它的代码检查和代码格式化功能。上述内容将受益于一些逻辑空白(特别是对于像我这样的老眼睛)和 4 点缩进(IMO)。一些唾手可得的成果包括 1) 我可以看到隐式 ByRef 在哪里可以使用 ByVal,使用已弃用的 CALL 关键字,当您可以使用特定类型和适当类的前缀时的通用类​​型,需要防止无限循环退出策略跨度>
  • 不必要的比较,例如Do While UILoading_Bool = True 可以是 Do While UILoading_Bool。您已经了解SendKeys 问题和对象焦点。 INT 其中Long 也可能是默认使用的。无论您是否希望遵循变量/子等的 VBA 案例规则......这些都是一些初始的低水果项目,与所使用的实际方法无关。很难对此发表评论,因为我无法复制您的位置。我已经概述了延迟加载的一般情况的常见解决方案。
  • Scroll_HTMLTable 中的 IF 行可能可以重新分解为一行,但这将涉及更全面地考虑测试,因为该测试非常了解何时加载完成。
猜你喜欢
  • 1970-01-01
  • 2013-10-02
  • 2016-09-26
  • 1970-01-01
  • 1970-01-01
  • 2016-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多