【问题标题】:Wait for window to reload when scrolling web page in VBA在VBA中滚动网页时等待窗口重新加载
【发布时间】:2017-03-29 21:10:32
【问题描述】:

我编写了一个 VBA 宏来计算 Google 搜索特定术语时返回的(大约)图像数量。近似我的意思是程序应该计算返回的图像数量,向下滚动以加载更多(如果适用)最多计算 400 个图像。这是(简化的)代码:

Sub GoogleCount ()

'''
'[Code to construct the URL ('fullUrl')]
'''
    Set objIE = New InternetExplorer
    objIE.navigate fullUrl
    Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
    Set currPage = objIE.document
    'Count images returned
    newNum = currPage.getElementById("rg_s").getElementsByTagName("IMG").Length
    'Scroll down until count = 400 (max) or no change in value
    Do While newNum >= 100 And newNum < 400 And newNum <> oldNum
        oldNum = newNum
        currPage.parentWindow.scrollBy 0, 100000
        Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
        newNum = currPage.getElementById("rg_s").getElementsByTagName("IMG").Length
    Loop

'''
'[Code to paste the value of newNum into my workbook, and do some other progress reporting]
'''
End Sub

我对滚动不满意,感觉非常'手动',尤其是当您以固定值滚动时(任何点让它动态?即找到页面的结尾并滚动到那里)

但主要问题是它不起作用:当我执行代码时,它会正确计算前 100 个(或更少)图像。但是当它应该滚动并计算更多时,我会返回 100 的值。用 F8 慢慢地遍历代码,我得到了正确的数字(最大 400),这让我得出结论,代码运行得太快了(我可能错了)。

为了减慢代码速度,我尝试添加 objIE.readyState 检查循环,但因为我只是在滚动,我不认为它算作页面“重新加载”,所以循环在等待新的循环时无效要加载的图像。

我考虑过添加一个时间延迟。我已经在工作了

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

在工作表的其他地方 - 所以,我可以添加小至毫秒级的延迟。

但我真的想避免使用它,因为这段代码是为 c 运行的。 50 种不同的搜索,并且已经花费了足够长的时间来执行,添加足够长的固定延迟以适应慢速连接速度并不理想。此外,互联网速度变化很大,以至于固定延迟非常不可靠 - 我可以进行某种连接测试以获得更好的大致数字,但最好的选择显然是只要你必须等待。

或者更好找到另一种计算图像的方法,最好是不涉及重新加载页面 4 次的方法! 有什么想法吗?

注意。如果您想自己调试,将fullUrl 设置为https://www.google.com/search?q=stack overflow|exchange&amp;tbm=isch&amp;source=lnt&amp;tbs=isz:ex,iszw:312,iszh:390 的良好图像搜索可能会返回>100 张但少于400 张的图像,因此您可以测试代码的各个方面

【问题讨论】:

  • 我建议您直接滚动到页面底部并返回最后一张图片的索引而不是使用循环

标签: html css vba excel


【解决方案1】:

通过进一步的研究,我想出了这种方法:

Dim myDiv As HTMLDivElement: Set myDiv = currPage.getElementById("fbar")
Dim elemRect As IHTMLRect: Set elemRect = myDiv.getBoundingClientRect
Do Until elemRect.bottom > 0
    currPage.parentWindow.scrollBy 0, 10000
    Set elemRect = myDiv.getBoundingClientRect
Loop
myDiv.ScrollIntoView

currPage 是 HTML 网页 (Dim currPage As HTMLDocument),myDiv 是特定元素。类型并不重要,但应注意myDiv 始终位于文档的底部并且 仅在其他所有内容完成后才加载。因此,对于 Google 图片,这是帮助栏,您只能在滚动浏览所有图片结果后才能看到。

工作原理

代码如下:myDiv.getBoundingClientRect 是一种检查元素在浏览器中是否可见的方法——这就是为什么我们需要查看页面底部的元素,如如果我们滚动直到它变得可见,那么其他所有内容也必须加载。

这当然是Do Until...Loop 的来源;我们循环直到elemRect.bottom 值不为零(因为当元素不在视图中时,它为零,一旦它在视图中,它就变为非零数)。更多信息请参阅here

最后,使用myDiv.ScrollIntoView 将浏览器置于底部;这是必要的,因为BoundingClientRect 在元素出现在屏幕上之前稍微可见,因此我们需要滚动最后一位以加载最终图像。

为什么不直接使用ScrollIntoView 作为开头?它不起作用,因为元素还没有加载。

【讨论】:

  • 注意。给任何为互联网相关的东西做 VBA 的人的建议,而不是仅仅搜索 vba 标签,搜索 javascript 也是如此。尽管语言的设置略有不同,但只要仔细观察,就可以将大部分语言转换为 VBA。我就是这样做的 - 没有 VBA 答案,但对于 Javascript(我会说!!)来说很多,但我可以很容易地应用到这个问题
【解决方案2】:

只需这样做,我相信您可以找到更好的方法(如果您认为值得花时间)但这应该没问题:

newNum = -1
Set objIE = New InternetExplorer
objIE.navigate fullUrl
Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
Set currPage = objIE.document
Do Until oldNum = newNum
    oldNum = newNum
    newNum = currPage.getElementById("rg_s").getElementsByClassName("rg_di rg_bx rg_el ivg-i").Length        
    Application.Wait Now + TimeSerial(0, 0, 2)
    currPage.parentWindow.scrollBy 0, 100000        
    Application.Wait Now + TimeSerial(0, 0, 2)
    If newNum > 400 Then newNum = 400
Loop

然后你只需要根据你的计算机加载速度来调整 TimeSerial 的延迟(在这里我设置为 2 秒)

【讨论】:

  • 也许这是一个想法,虽然我不认为循环对计算时间有太大影响,它只是计算一个数字。但是我认为您错过了要点,我需要在滚动时加载页面。也许我应该解释得更好,但是当我发送“滚动”命令时,Google 只会滚动到它已加载图像,然后停止(所以我需要再次发送命令)。这提供了 2 个选项。我等待一段编码时间,直到下一组图像(100 多个)完全加载。这样我只需滚动 4 次以确保加载所有 400 张图像。或者我滚动直到...发生
  • 如果有办法继续滚动直到 a) 加载了 400 张图像或 b) 不再加载图像,则使用第二个选项。我已经达到了结果的结尾——这可能就是我所追求的。我想对于 a) 我只是一遍又一遍地发送滚动,直到 count = 400,不理想 因为我也必须一遍又一遍地计数,这会减慢速度。但是 b) 更难,如果我可以检测到下一个图像何时完成加载,那么我可以查看是否一切都已完成,并且尝试滚动是否没有效果,这意味着我已经到达页面的末尾。我只是不知道该怎么做。
  • 要求更多解释,我无法编辑以澄清我的措辞。但一般来说,您的行currPage.parentWindow.scrollBy 0, 10000000 不会滚动到页面上的最后一个图像(第 400 个或更少的图像较少的页面),它只会滚动到第 100 个然后停止。这就是我迭代的原因,等到图像加载完毕然后再滚动一些以加载下一组
  • 我明白你想做什么。您是否尝试实施我的建议?它确实向下滚动整个页面并检索所有图片(至少我尝试使用您的链接并且它有效)
  • 我已经尝试过了,发现了几个问题:正如我所提到的,Google 以 100 个为一组加载图像(至少对我而言!)。滚动到第一组的末尾100 张图像触发下一组加载。实际上,对于我提供的链接,您的代码currPage.parentWindow.scrollBy 0, big number 确实会触发所有 170 个左右的图像加载,因为代码滚动到第一个 100 的末尾并触发下一个 100 的加载。因为 170 在 200 以内,您的代码触发所有要加载的图像,到目前为止很好。
猜你喜欢
  • 2013-11-24
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
相关资源
最近更新 更多