12

我正在使用 .NET WebBrowser 控件。我如何知道网页何时完全加载?

我想知道浏览器何时不再获取任何数据。(IE 在其状态栏中写入“完成”的那一刻......)。

笔记:

  • 对于包含多个框架的网站,DocumentComplete/NavigateComplete 事件可能会发生多次。
  • 浏览器就绪状态也不能解决问题。
  • 我尝试检查帧集合中的帧数,然后计算我得到 DocumentComplete 事件的次数,但这也不起作用。
  • this.WebBrowser.IsBusy 也不起作用。在 Document Complete 处理程序中检查它时始终为“假”。
4

12 回答 12

3

以下是我在应用程序中解决问题的方法:

private void wbPost_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url != wbPost.Url)
        return;
    /* Document now loaded */
}
于 2010-02-24T21:26:27.577 回答
2

在页面完全加载(包括框架)时做某事的方法是这样的:

using System.Windows.Forms;
    protected delegate void Procedure();
    private void executeAfterLoadingComplete(Procedure doNext) {
        WebBrowserDocumentCompletedEventHandler handler = null;
        handler = delegate(object o, WebBrowserDocumentCompletedEventArgs e)
        {
            ie.DocumentCompleted -= handler;
            Timer timer = new Timer();
            EventHandler checker = delegate(object o1, EventArgs e1)
            {
                if (WebBrowserReadyState.Complete == ie.ReadyState)
                {
                    timer.Dispose();
                    doNext();
                }
            };
            timer.Tick += checker;
            timer.Interval = 200;
            timer.Start();
        };
        ie.DocumentCompleted += handler;
    }

从我的其他方法中,我学到了一些“不要”-s:

  • 不要试图弯曲勺子...... ;-)
  • 不要尝试使用 DocumentComplete、Frames、HtmlWindow.Load 事件构建复杂的构造。如果您的解决方案完全有效,您的解决方案将是脆弱的。
  • 不要使用System.Timers.Timer代替Windows.Forms.Timer,如果你这样做,奇怪的错误将开始在奇怪的地方发生,因为计时器运行在与你的应用程序的其余部分不同的线程上。
  • 不要只使用没有 DocumentComplete 的 Timer,因为它可能会在您的页面甚至开始加载之前触发,并且会过早地执行您的代码。
于 2010-01-31T17:22:48.123 回答
2

这是我的测试版本。只需将此作为您的DocumentCompleted Event Handler并将您只想调用一次的代码放入方法OnWebpageReallyLoaded()中。实际上,这种方法确定页面何时稳定了 200 毫秒,然后执行它的操作。

// event handler for when a document (or frame) has completed its download
Timer m_pageHasntChangedTimer = null;
private void webBrowser_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e ) {
    // dynamic pages will often be loaded in parts e.g. multiple frames
    // need to check the page has remained static for a while before safely saying it is 'loaded'
    // use a timer to do this

    // destroy the old timer if it exists
    if ( m_pageHasntChangedTimer != null ) {
        m_pageHasntChangedTimer.Dispose();
    }

    // create a new timer which calls the 'OnWebpageReallyLoaded' method after 200ms
    // if additional frame or content is downloads in the meantime, this timer will be destroyed
    // and the process repeated
    m_pageHasntChangedTimer = new Timer();
    EventHandler checker = delegate( object o1, EventArgs e1 ) {
        // only if the page has been stable for 200ms already
        // check the official browser state flag, (euphemistically called) 'Ready'
        // and call our 'OnWebpageReallyLoaded' method
        if ( WebBrowserReadyState.Complete == webBrowser.ReadyState ) {
            m_pageHasntChangedTimer.Dispose();
            OnWebpageReallyLoaded();
        }
    };
    m_pageHasntChangedTimer.Tick += checker;
    m_pageHasntChangedTimer.Interval = 200;
    m_pageHasntChangedTimer.Start();
}

OnWebpageReallyLoaded() {
    /* place your harvester code here */
}
于 2010-04-13T14:28:11.303 回答
0

你试过WebBrowser.IsBusy房产吗?

于 2009-03-23T13:11:49.830 回答
0

当帧完成时,在每个帧中使用 javascript 设置一个标志,然后让 C# 查看标志如何?

于 2009-03-23T13:33:40.153 回答
0

我没有其他选择,但我想知道 Document Complete 处理程序期间的IsBusy属性是否true是因为处理程序仍在运行,因此WebBrowser控制在技术上仍然“忙碌”。

最简单的解决方案是有一个每 100 毫秒左右执行一次的循环,直到IsBusy标志被重置(在出现错误的情况下具有最大执行时间)。当然,这假设在页面加载期间的任何时候IsBusy都不会设置为false

如果 Document Complete 处理程序在另一个线程上执行,您可以使用锁将主线程发送到睡眠状态并从 Document Complete 线程中唤醒它。然后检查IsBusy标志,重新锁定主线程仍然是true.

于 2009-03-23T13:45:52.137 回答
0

我不确定它是否会起作用,但请尝试在您的框架集上添加一个 JavaScript“onload”事件,如下所示:

function everythingIsLoaded() { alert("everything is loaded"); }
var frameset = document.getElementById("idOfYourFrameset");
if (frameset.addEventListener)
    frameset.addEventListener('load',everythingIsLoaded,false); 
else
    frameset.attachEvent('onload',everythingIsLoaded); 
于 2009-03-25T15:22:37.503 回答
0

可以使用 jQuery 吗?然后,您可以轻松地在目标帧上绑定帧就绪事件。有关说明,请参阅答案。这篇博文也有关于它的讨论。最后,您可以使用一个插件。

这个想法是您使用以下方法计算网页中的帧数:

$("iframe").size()

然后计算 iframe 就绪事件被触发的次数。

于 2009-03-26T07:35:30.440 回答
0

您将获得外部网页以及每个框架的 BeforeNavigate 和 DocumentComplete 事件。当您收到外部网页的 DocumentComplete 事件时,您就知道您已经完成了。您应该能够使用IWebBrowser2::TopLevelContainer()的托管等效项来确定这一点。

但是请注意,网站本身可以随时触发更多框架导航,因此您永远不知道页面是否真的永远完成。您可以做的最好的事情是记录您看到的所有 BeforeNavigates,并在您获得 DocumentComplete 时减少计数。

编辑:这是托管文档:TopLevelContainer

于 2009-03-26T07:39:11.087 回答
0

这是最终对我有用的方法:

       public bool WebPageLoaded
    {
        get
        {
            if (this.WebBrowser.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
                return false;

            if (this.HtmlDomDocument == null)
                return false;

            // iterate over all the Html elements. Find all frame elements and check their ready state
            foreach (IHTMLDOMNode node in this.HtmlDomDocument.all)
            {
                IHTMLFrameBase2 frame = node as IHTMLFrameBase2;
                if (frame != null)
                {
                    if (!frame.readyState.Equals("complete", StringComparison.OrdinalIgnoreCase))
                        return false;

                }
            }

            Debug.Print(this.Name + " - I think it's loaded");
            return true;
        }
    }

在每个文档完成事件上,我都会遍历所有 html 元素并检查所有可用的帧(我知道它可以被优化)。对于每一帧,我检查它的就绪状态。它非常可靠,但就像 jeffamaphone 所说,我已经看到一些网站触发了一些内部刷新。但是上面的代码满足了我的需求。

编辑:每一帧都可以包含其中的帧,所以我认为应该更新这段代码以递归检查每一帧的状态。

于 2009-03-26T10:12:10.987 回答
0

我只是使用 webBrowser.StatusText 方法。当它说“完成”时,一切都已加载!还是我错过了什么?

于 2010-03-30T20:54:38.577 回答
0

检查 IE.readyState = READYSTATE_COMPLETE 应该可以工作,但如果这对您来说不可靠并且您确实想知道“IE 在其状态栏中写入'完成'的那一刻”,那么您可以循环直到 IE.StatusText 包含“完毕”。

于 2011-11-03T04:10:39.007 回答