【问题标题】:In Excel VBA, what is the way to check if the web page is fully loaded?在 Excel VBA 中,检查网页是否已完全加载的方法是什么?
【发布时间】:2018-04-14 05:43:36
【问题描述】:

要暂停代码直到网页完全加载,我几乎一直都在使用下面的方法并取得了巨大的成功。

Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop

但偶尔,我会看到在该方法确定页面已完全加载后加载文本内容,因此未提取内容。

但是,如果我通过 F8 单步执行代码,则每次都会提取内容。这与我重复按 F8 键的速度一样快。

那么在代码继续提取数据之前,如何检查以确保页面及其所有内容已完全加载?

在这两种情况下,IE 都在不可见地运行。但是,我已经在 IE 可见的情况下进行了尝试,并且在我正在使用的页面上的这个特定位置实际上有内容。

这是在 Excel 2016 中使用 VBA 脚本完成的。具体的内容请求写成这样:

 'get item name from page and write it to the first cell on the first empty row available
 Set itemName = objIE.document.querySelector(".the-item-name")
 Worksheets("Results").Range("A1048576").End(xlUp).Offset(1, 0).Value = itemName.innerText

我已经阅读了Excel VBA: Wait for JavaScript execution in Internet Explorer,因为我认为可能是在加载文档后添加了这些值,以防止任何人抓取数据。但是,我似乎无法识别任何可能这样做的脚本。并不意味着它不存在。我只是还看不到它。

存在此问题的页面的一个具体示例是 URL

https://www.homedepot.ca/en/home/p.dry-cloth-refills-32---count.1000660019.html

最初product-total-price div 元素在加载价格之前包含破折号 (-),所以这就是请求将返回的内容:- / each 而不是 $11.29 / each

我有一个解决方法,但它不像我希望的那样高效或简洁。我测试返回的字符串是否存在破折号。如果它在那里,循环并再次检查它,否则捕获它并将其插入到工作表中。

setPriceUM:
    Set hdPriceUM = objIE.document.querySelector(".product-total-price").innerTe‌​‌​xt
    hdPriceUMString = hdPriceUM.innerText
    stringTest = InStr(hdPriceUMString, "-")
    If stringTest = True Then
        GoTo setPriceUM
    Else
        Debug.Print hdPriceUMString
    End If

感谢您花时间阅读并考虑它。

【问题讨论】:

  • 很好的问题。我也在努力解决这个问题,但幸运的是,我一直解决我的问题的一种方法是在包含 .Busy 的初始循环之后添加一个循环 - 循环直到我的对象可用。所以,我的问题是:页面完全“加载”后所有对象都可用吗?示例:你Set SubmitBtn = doc.getElement........是Nothing,提示运行时错误?
  • 我也遇到过这个问题,不过一般是网络问题。当网络快速运行时,没有问题,但是当它开始显示一些延迟时,页面没有完全加载。我不得不求助于添加一个等待计时器来留出额外的时间。 Application.Wait (Now + TimeValue("0:00:06")) 等待 6 秒。
  • @Mitch Timers 是不可靠的解决方案,尤其是对于慢速网络。
  • @omegastripes 我完全同意。我们的内部网站都是使用 kendo-ui 完成的,对我来说,这很难弄清楚。我们的位置有 4 个 T1,您不会认为网络延迟会是一个问题,但它偶尔会发生。大多数问题在于我们访问同一系统的众多用户,然后服务器与 SQL 服务器进行通信。我仍然想知道为什么我们不在 Unix 系统(服务器端)上运行所有东西。哦,好的,谢谢你的评论!我努力坚持下去。

标签: vba excel internet-explorer web-scraping


【解决方案1】:

网页的功能非常不同,因此没有适合所有网页的解决方案。

关于您的示例,您的解决方法是一个可行的解决方案,代码可能如下:

Sub TestIE()

    Dim q

    With CreateObject("InternetExplorer.Application")
        .Visible = True
        .Navigate "https://www.homedepot.ca/en/home/p.dry-cloth-refills-32---count.1000660019.html"
        ' Wait IE
        Do While .readyState < 4 Or .Busy
            DoEvents
        Loop
        ' Wait document
        Do While .document.readyState <> "complete"
            DoEvents
        Loop
        ' Wait element
        Do
            q = .document.querySelector(".product-total-price").innerText
            If Left(q, 1) <> "-" Then Exit Do
            DoEvents
        Loop
        .Quit
    End With
    Debug.Print q

End Sub

无论如何,您需要使用浏览器开发工具 (F12) 查看网页加载过程、XHR 和 DOM 修改。这样一来,您可能会发现众多 XHR 之一以 JSON 格式返回价格。它在页面加载时出现价格之前登录浏览器开发工具的网络选项卡。该 XHR 是由加载的 JS 之一制作的,特别是在页面加载事件之后。试试这个网址(我刚刚从网络标签复制了它):

https://www.homedepot.ca/homedepotcacommercewebservices/v2/homedepotca/products/1000660019/localized/9999?catalogVersion=Online&lang=en

所以你可以复制 XHR 并通过拆分提取价格:

Sub TestXHR()

    Dim q

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://www.homedepot.ca/homedepotcacommercewebservices/v2/homedepotca/products/1000660019/localized/9999?catalogVersion=Online&lang=en", False
        .Send
        q = .ResponseText
    End With
    q = Replace(q, " : ", ":")
    q = Split(q, """displayPrice""", 2)(1)
    q = Split(q, """formattedValue"":""", 2)(1)
    q = Split(q, """", 2)(0)
    Debug.Print q

End Sub

但同样,没有常见的情况。

你也可以使用 JSON 解析器,看看some examples

【讨论】:

  • Omegastripes,你在第一个代码 sn-p 中所做的几乎与我的解决方法相同,所以我的编码质量正在提高,这让我感到鼓舞。 XHR 对我来说是新事物,自从大约 15 年前它首次出现以来,我还没有做过任何 JSON 工作。我会加快这两个方面的速度。我上周才开始研究 MSXML2.XMLHTTP 函数。我相信你是对的,这是要走的路。我会在工作中试一试,然后在这里报告。谢谢!
猜你喜欢
  • 2013-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多