c# WebBrowser DocumentText 工作一次但不在循环中?

Posted

技术标签:

【中文标题】c# WebBrowser DocumentText 工作一次但不在循环中?【英文标题】:c# WebBrowser DocumentText works once but not in a loop? 【发布时间】:2013-08-25 18:05:13 【问题描述】:

我有兴趣检查网站的内容,内容经常变化,当我在任何浏览器上查看该网站时,它每 30 秒刷新一次。我想知道内容何时发生变化。

我正在使用 winforms,我只想单击一个按钮来开始一个循环,每 30 秒一次。我不想太频繁地访问网站,其实网页本身的刷新已经足够满足我的需要了。

我的代码在我单击按钮 (btnCheckWebsite) 时有效,如果我稍等片刻然后再次单击 btnCheckWebsite,我的消息框会弹出,因为网页已更改。这很好,但是我想在 while 循环中执行此操作。当我取消注释我的 while 循环时, DocumentText 永远不会改变。我已经对其进行了调试,由于某种原因,它每次都是相同的文本,即使网页在现实世界中发生了变化,它在我的代码中也保持不变。

所以我的问题是为什么我不能使用循环,我可以做些什么来重复运行它而不需要我的任何输入?

作为奖励,我想删除我添加的 .Refresh() ,因为没有它它就无法工作,但是据我所知,这会刷新整个页面。当我使用浏览器时,即使我没有刷新整个页面,我也会看到页面更新。

仅作为背景信息,我确实首先在我的表单上有一个 WebBrowser 控件,页面会自动刷新。我使用了相同的代码并遇到了同样的问题,有趣的是,我的 windows 窗体上的 WebBrowser 控件自行刷新没问题,直到我单击 btnCheckWebsite 然后它停止刷新!我也知道 webrequest,但我不知道如何将它用于我的目的。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Check_Website

    public partial class Form1 : Form
    
        public WebBrowser _memoryWebBrowser = new WebBrowser();
        String _previousSource = "emptySource";

        public Form1()
        
            InitializeComponent();

           _memoryWebBrowser.Navigate(new Uri("http://www.randomurl.com/"));

        

        private void btnCheckWebsite_Click(object sender, EventArgs e)
        
            //I want to un-comment this while loop and let my code run itself but it stops working
            //when I introduce my while loop.

            //while (1 < 2 )
            //
                //Thread.Sleep(30000);

                checkWebsite();

            //
        

        private void checkWebsite()
        
            //Why do I need this refresh? I would rather not have to hit the web page with a refresh.
            //When I view the webpage it refreshed with new data however when I use a WebBrowser
            //the refresh just doesn't happen unless I call Refresh.
            _memoryWebBrowser.Refresh();

            Thread.Sleep(500);

            while (((_memoryWebBrowser.ReadyState != WebBrowserReadyState.Complete) || (_memoryWebBrowser.DocumentText.Length < 3000)))
            
                Thread.Sleep(1000);
            


            String source = _memoryWebBrowser.DocumentText;

            if ((source != _previousSource) && (_previousSource != "emptySource"))
            
                //Hey take a look at the interesting new stuff on this web page!!
                MessageBox.Show("Great news, there's new stuff on this web page www.randomurl.co.uk!!" );
            

            _previousSource = source;

        
    

【问题讨论】:

明确您的页面是使用 AJAX 还是 Dhtml 来动态更新自身,并且您希望跟踪这些更改。 [UPDATE]我们澄清了页面确实是动态更新的,解决方案是使用Document.Document.Body.OuterHtml来跟踪更新。 【参考方案1】:

您需要对DocumentCompleted 事件进行处理。此事件是异步的,因此如果您想在循环中执行此操作,执行线程必须泵送消息以触发此事件。在 WinFroms 应用程序中,您的 UI 线程已经在Applicaiton.Run 中发送消息,并且在同一线程上进入嵌套消息循环的唯一其他认可方式是通过模态表单(这是it can be done 的方式,请参阅 cmets)。 另一种(IMO,更好的)在没有嵌套消息循环的情况下执行 Navigate/DocumentCompleted 逻辑的方法是使用 async/await、here's how。在经典意义上,这并不完全是一个循环,但从概念和语法上讲,它可能正是您要寻找的。​​p>

【讨论】:

这可行,但与到目前为止的其他 3 个答案一样,它实际上只是重复加载网页的另一种方式。理想情况下,我想加载网页一次,然后检查网页内发生的小变化。该网页有一个控件,其中包含我希望看到的更改内容。在浏览器中,内容会更改而无需重新加载网页,这就是我想要以编程方式执行的操作。 据我所知,您的页面使用 AJAX 或 DHTML 来动态更新自身 - 如果我错了,请纠正我。如果是这样,你应该在你的问题中说清楚。无论如何,在这种情况下,您只需要处理一次DocumentCompleted。然后不要使用DocumentText,而是使用Document.Document.Body.OuterHtml 来跟踪动态变化。可能有更好的处理方法,例如this。 完美!我需要做的就是使用 _memoryWebBrowser.Document.Body.OuterHtml;而不是 _memoryWebBrowser.DocumentText;在我的解决方案中!是的,该页面确实使用 AJAX 或类似方法来仅更新少量内容。我说的刷新是指只有一个控件刷新少量内容,整个页面不会重新加载。 我现在已经注释掉了我的刷新 //_memoryWebBrowser.Refresh();它仍然可以完美运行,这证明这是加载页面一次,然后在不刷新或重新加载页面的情况下找到更改。再次感谢!【参考方案2】:

您可以捕获 WebBrowser.Navigated 事件以在页面重新加载时获得通知。所以你不需要一个循环。 (我指的是就绪循环)

只需每 30 秒循环一次导航到页面,在导航事件中,您可以检查网站是否已更改。

【讨论】:

听起来不错,但我不确定页面是否真的重新加载。该页面大部分保持静态,但页面中有一个控件可以更改内容。我确信他们已经这样做了,无需重新加载页面即可显示新内容。【参考方案3】:

你最好挂上 DocumentCompleted 事件来检查它的 DocumentText 属性!

【讨论】:

这在 DocumentCompleted 时会起作用,但只会发生一次。我怎样才能反复检查差异? 在Documentcomplete中检查差异后,调用_memoryWebBrowser.Refresh(); 如何让它循环,如果我让它循环,我怎么知道它没有重新加载页面?可能我不明白,你有例子吗?【参考方案4】:

WebBrowser 元素有很多错误,并且需要大量开销来满足您的需求。相反,您应该使用 WebRequest。因为您说您不知道如何使用,所以这里有一个(工作)示例供您使用。

using System;
using System.Windows.Forms;
using System.Net;
using System.IO;

namespace Check_Website

    public partial class Form1 : Form
    
        String _previousSource = string.Empty;
        System.Windows.Forms.Timer timer;

        private System.Windows.Forms.CheckBox cbCheckWebsite;
        private System.Windows.Forms.TextBox tbOutput;

        public Form1()
        
            InitializeComponent();

            this.cbCheckWebsite = new System.Windows.Forms.CheckBox();
            this.tbOutput = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // cbCheckWebsite
            // 
            this.cbCheckWebsite.AutoSize = true;
            this.cbCheckWebsite.Location = new System.Drawing.Point(12, 12);
            this.cbCheckWebsite.Name = "cbCheckWebsite";
            this.cbCheckWebsite.Size = new System.Drawing.Size(80, 17);
            this.cbCheckWebsite.TabIndex = 0;
            this.cbCheckWebsite.Text = "checkBox1";
            this.cbCheckWebsite.UseVisualStyleBackColor = true;
            // 
            // tbOutput
            // 
            this.tbOutput.Location = new System.Drawing.Point(12, 35);
            this.tbOutput.Multiline = true;
            this.tbOutput.Name = "tbOutput";
            this.tbOutput.Size = new System.Drawing.Size(260, 215);
            this.tbOutput.TabIndex = 1;
            // 
            // Form1
            // 
            this.ClientSize = new System.Drawing.Size(284, 262);
            this.Controls.Add(this.tbOutput);
            this.Controls.Add(this.cbCheckWebsite);
            this.Name = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

            timer = new System.Windows.Forms.Timer();
            timer.Interval = 30000;
            timer.Tick += timer_Tick;
        

        private void Form1_Load(object sender, EventArgs e)
        
            timer.Start();
        

        void timer_Tick(object sender, EventArgs e)
        
            if (!cbCheckWebsite.Checked) return;

            WebRequest request = WebRequest.Create("http://localhost/check_website.html");
            request.Method = "GET";

            WebResponse response = request.GetResponse();

            string newContent;
            using (var sr = new StreamReader(response.GetResponseStream()))
            
                newContent = sr.ReadToEnd();
            

            tbOutput.Text += newContent + "\r\n";

            if (_previousSource == string.Empty)
            
                tbOutput.Text += "Nah. It's empty";
            
            else if (_previousSource == newContent)
            
                tbOutput.Text += "Nah. Equals the old content";
            
            else
            
                tbOutput.Text += "Oh great. Something happened";
            

            _previousSource = newContent;
        
    

【讨论】:

这很好用,我同意使用 WebBrowser 会产生开销。这种开销会影响我的 Windows 窗体,但这并不让我担心。唯一的小问题是 request.GetResponse();在此解决方案中,再次加载整个网页。它与 .Refresh(); 相同。在我的解决方案中,我想避免每 30 秒执行一次。实际上,这是我想要检查的内容,因为它会动态变化。 90% 的网页是静态的,所以我不想每次都重新加载它。有没有办法只加载一次网页,然后只检查变化的内容? 只是补充一下,这是一个很好的例子,但我的答案是使用 _memoryWebBrowser.Document.Body.OuterHtml;而不是 _memoryWebBrowser.DocumentText;这只是我现有代码中的 1 行更改,然后我能够注释掉我的 _memoryWebBrowser.Refresh();这完美地实现了我的最终目标,因为我加载了一次网页,然后不刷新页面,我正在检查动态变化的内容。 WebBrowser 开销不是问题,因为它只发生一次。我的循环中的效率更重要,即不使用 Refresh 或 GetResponse() 重新加载。 在你的问题中你说网站的内容经常变化。这可以被视为 a) 有人更改了代码或 b) 您在网站上有 AJAX(或类似的)并且只是一点点内容更改。因此,我认为您希望每 30 秒获取整个页面并将其与前一个页面进行比较。一点也不!很高兴看到你自己解决了。

以上是关于c# WebBrowser DocumentText 工作一次但不在循环中?的主要内容,如果未能解决你的问题,请参考以下文章

C# webbrowser怎么判断登录是不是成功?

我如何在 webBrowser 中使用 c# 执行点击事件

如何在 C# 中使用 WebBrowser 控件清除浏览历史记录

C# webbrowser如何打开https开头的网页

如何在 C# 中更新 WebBrowser 控件中的 DOM 内容?

C# winform webbrowser如何指定内核为IE11?