VBA Internet Explorer 等待网页加载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19933313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
VBA Internet Explorer wait for web page to load
提问by MattB
I know questions like this have been asked before, but mine is a bit different and has been fairly troubling. What I'm dealing with is a web page with a form with a few events that load more of the page when certain items in input boxes are filled out. When these events fire the page loads again, but remains at the same URL with the same nameprop. I've been using the following types of methods both seperately and strung together to handle waiting for the page to load, but sometimes the VBA still manages to continue executing and set the HTMLDocument variable to a page without the appropriate information on it causing the macro to debug. Here are the kinds of things I've been trying so far:
我知道以前有人问过这样的问题,但我的有点不同,而且相当麻烦。我正在处理的是一个带有一些事件的表单的网页,当输入框中的某些项目被填写时,这些事件会加载更多的页面。当这些事件触发时,页面将再次加载,但仍保留在具有相同 nameprop 的相同 URL 中。我一直在使用以下类型的方法,单独和串在一起来处理等待页面加载,但有时 VBA 仍然设法继续执行并将 HTMLDocument 变量设置为页面,而页面上没有适当的信息导致宏调试。以下是我迄今为止一直在尝试的事情:
While IE.Busy
DoEvents
Wend
Do Until IE.statusText = "Done"
DoEvents
Loop
Do Until IE.readyState = 4
DoEvents
Loop
I've even attempted to place these events into a loop like the following, but it didn't quite work because the lastModified property only returns a value down to the second and the macro spins through the fields fast enough that it is returning a new page in the same second:
我什至试图将这些事件放入如下所示的循环中,但它并没有完全奏效,因为 lastModified 属性只返回一个向下到第二个的值,并且宏以足够快的速度旋转字段以返回一个新的同一秒页面:
Do Until IE.statusText = "Done" And IE.Busy = False And IE.ReadyState = 4 _
And IE.document.lastModified > LastModified ----or---- IE.document.nameprop = _
"some known and expected name prop here"
While IE.Busy
DoEvents
Wend
Do Until IE.statusText = "Done"
DoEvents
Loop
Do Until IE.readyState = 4
DoEvents
Loop
Loop
Even that fails to wait long enough to set the HTMLDocument object leading to a debug. I've contemplated setting the next input element and checking that for nothing to further the code, but even that wouldn't be successful 100% of the time because generally the Input elements exist in the HTML but are hidden until the appropriate event is fired, which wouldn't be a problem but they don't load their possible selections until after the event is fired. It might be an odd page.
即使这样也无法等待足够长的时间来设置导致调试的 HTMLDocument 对象。我已经考虑设置下一个 input 元素并检查它以进一步推进代码,但即使这样也不会 100% 成功,因为通常 Input 元素存在于 HTML 中,但在触发适当的事件之前是隐藏的,这不会有问题,但在事件触发之前他们不会加载可能的选择。它可能是一个奇怪的页面。
Anyway... not sure what else to add. If there is something else that might be helpful to see just ask. I guess what I'm looking for is a way to get VBA to wait until IE knows another page isn't on it's way. It seems to load a few times before it is completely done.
无论如何......不知道还有什么要添加的。如果还有其他可能有助于查看的内容,请询问。我想我正在寻找的是一种让 VBA 等待 IE 知道另一个页面不在路上的方法。它似乎在完全完成之前加载了几次。
So... Anyone have any ideas?
所以......有人有任何想法吗?
EDIT: Found a few new things to try. Still, no dice. It was suggested that I add these attempts. Here is the code, for some reason the VBE and excel instance become non-responsive when using this approach after firing an event that should populate the options on the select element... thinking about trying xml... here is the code:
编辑:找到了一些新的尝试。仍然没有骰子。有人建议我添加这些尝试。这是代码,由于某种原因,在触发应填充 select 元素上的选项的事件后使用此方法时,VBE 和 excel 实例变得无响应...考虑尝试 xml...这里是代码:
intCounter = 0
Do until intCounter > 2
Do Until IE.Busy = False: DoEvents: Loop
Do Until IE.ReadyState = 4: DoEvents: Loop
Set HTMLDoc = IE.Document
Do Until HTMLDoc.ReadyState = "complete"
Set HTMLSelect = HTMLDoc.getElementById("ctl00$ctl00$MainContent$ChildMainContent$ddlEmployeeBranchCodes")
intCounter = 0
For each Opt in HTMLSelect
intCounter = intCounter + 1
Next Opt
Loop
Based on what I can see happening on the web page, I know that it is somewhere in this loop that the VBE and Excel become non-responsive.
根据我在网页上看到的情况,我知道在这个循环中的某个地方 VBE 和 Excel 变得无响应。
Hope that helps... I know it didn't help me... Drats.
希望有帮助...我知道它没有帮助我... Drats。
EDIT: Just thought I'd add this. When it comes to automating a web page, for the most part, I no longer use IE. I've found it's much better, and sidesteps this issue of async stuff entirely, to simply perform the posts and gets yourself. May not be the best solution depending on what you're trying to do, but it works pretty reliably if you look at the traffic closely and parameterize things well.
编辑:只是想我会添加这个。当谈到自动化网页时,在大多数情况下,我不再使用 IE。我发现它要好得多,并且完全避免了异步问题的问题,只需执行帖子并获得自己。可能不是最好的解决方案,具体取决于您要做什么,但如果您仔细查看流量并很好地参数化,它会非常可靠地工作。
采纳答案by MattB
After an exhaustive search, I've determined that the AJAX request, javascript code that runs asynchronously in the background isn't something I can get a signal from in any way. It does seem to trigger some event when it finishes with loading the page, which is an option I'd like to explore in the future. However, for my purposes I simply used the same code I was already using to fill out the form on my page and I have it loop through each field again to check to see if the values are still correct before clicking the submit button. It isn't an ideal solution, but it is a workaround that appears to have taken care of my issue in this case.
经过详尽的搜索,我确定 AJAX 请求,在后台异步运行的 javascript 代码不是我可以以任何方式获取信号的东西。当它完成加载页面时,它似乎确实会触发一些事件,这是我将来想探索的一个选项。但是,出于我的目的,我只是使用了我已经用来填写页面上的表单的相同代码,并让它再次循环遍历每个字段,以在单击提交按钮之前检查值是否仍然正确。这不是一个理想的解决方案,但它是一种解决方法,在这种情况下似乎已经解决了我的问题。
I'm not sure if my solution would be applicable to someone else dealing with this issue, but there it is if it helps. I think workarounds for this issue are going to have to be based on the application and web page in question.
我不确定我的解决方案是否适用于处理这个问题的其他人,但如果它有帮助的话。我认为此问题的解决方法必须基于相关应用程序和网页。
回答by Greedo
Old question I know, but I think this is a good answer that I haven't seen about much...
我知道的老问题,但我认为这是一个很好的答案,我很少看到......
I had a similar problem; waiting for all the images on a google image search to load (which is a tricky thing since image loads are prompted by AJAX and the user scrolling the page). As has been suggested in the comments; my solutionwas to wait for a certain element to appear in the viewport(this is an area a little larger than the monitor screen, and is treated as what you can actually "see").
我有一个类似的问题;等待谷歌图像搜索上的所有图像加载(这是一件棘手的事情,因为图像加载是由 AJAX 提示的,用户滚动页面)。正如评论中所建议的那样;我的解决方案是等待某个元素出现在视口中(这是一个比监视器屏幕稍大的区域,并被视为您实际可以“看到”的区域)。
This is achieved with the getBoundingClientRect
method
这是通过getBoundingClientRect
方法实现的
Dim myDiv As HTMLDivElement: Set myDiv = currPage.getElementById("fbar")
'myDiv should some element in the page which will only be visible once everything else is loaded
Dim elemRect As IHTMLRect: Set elemRect = myDiv.getBoundingClientRect
Do Until elemRect.bottom > 0 'If the element is not in the viewport, then this returns 0
DoEvents
'Now run the code that triggers the Ajax requests
'For me that was simply scrolling down by a big number
Set elemRect = myDiv.getBoundingClientRect
Loop
myDiv.ScrollIntoView
I explain in detail in the linked answer how this works, but essentially the BoundingClientRect.bottom
is equal to 0 until the element is in the vieport.
我在链接的答案中详细解释了这BoundingClientRect.bottom
是如何工作的,但基本上等于 0,直到元素位于 vieport 中。
The element is something which is loaded straight away (like a frame/template for the page). But you don't actually see it until all the content has been loaded, because it's right at the bottom.
元素是直接加载的东西(如页面的框架/模板)。但是在加载所有内容之前您实际上不会看到它,因为它就在底部。
If that element is indeed the last thing to be loaded (for my google search it was the Show More Resultsbutton), then as long as you get it into the viewport when it's loaded, you should be able to detect when it appears on the page. .bottom
then returns a non-zero value (something to do with the actual position of the element on the page - I didn't really care though for my purposes). I finish off with a .ScrollIntoView
, but that's not essential.
如果该元素确实是最后要加载的东西(对于我的谷歌搜索,它是Show More Results按钮),那么只要您在加载时将其放入视口,您就应该能够检测到它何时出现在页面上。.bottom
然后返回一个非零值(与元素在页面上的实际位置有关 - 我并不真正关心我的目的)。我以 结束.ScrollIntoView
,但这不是必需的。
回答by Deepak
I had the same problem with My Webpage.. What is did is...
我的网页也有同样的问题..所做的是......
the fist option is
第一个选项是
While Ie.**document**.readystate="complete"
DoEvents
Wend
there were few boxes in which options were loaded after a button click/even fire in another box...I jsst placed code like this..
单击按钮后加载选项的框很少/甚至在另一个框中触发...我jsst放置了这样的代码..
Do Until IE.document.getelementbyid("Next box").Lenght>0
DoEvents
Loop
Application.wait Now+Timevalue("00:00:02)