2013-08-22 24 views
0

我對檢查網站內容感興趣,內容經常更改,當我在任何瀏覽器上查看網站時,它每隔30秒刷新一次。我想知道內容何時發生變化。c#WebBrowser DocumentText工作但不在循環中?

我正在使用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; 

     } 
    } 
} 
+0

說明您的頁面是否使用AJAX或DHTML動態更新自己,並且您想跟蹤這些更改。 – Noseratio

+0

** [更新] **我們澄清了頁面確實動態更新了自己,解決方案是使用'Document.Document.Body.OuterHtml'來跟蹤更新。 – Noseratio

回答

1

您需要在DocumentCompleted事件中進行處理。這個事件是異步的,所以如果你想在循環中這樣做,執行線程必須爲這個事件激發消息。在WinFroms應用程序中,您的UI線程已經在Applicaiton.Run中抽取消息,並且唯一其他認可的在同一線程上輸入嵌套消息循環的方式是通過模態窗體(請參見注釋中的it can be done)。 另一個(IMO,更好的)做這樣的Navigate/DocumentCompleted沒有嵌套消息循環的邏輯是通過使用async/await,here's how。從經典的角度來說,這不完全是一個循環,但從概念上和語法上來說,它可能正是你正在尋找的東西。

+0

這將工作,但與其他3個答案一樣,它實際上只是不同的方式來重複加載網頁。理想情況下,我想加載一次網頁,然後檢查網頁中發生的小變化。這個網頁有一個控制着我想要改變的內容。在瀏覽器中,內容變化而不重新加載網頁,這就是我想要以編程方式進行的。 – Ewan

+0

現在我知道了,你的頁面使用AJAX或DHTML動態更新自己 - 糾正我,如果我錯了。如果是這樣,你應該在你的問題中說清楚。無論如何,在這種情況下,你只需要處理一次'DocumentCompleted'。那麼不要使用'DocumentText',而是使用'Document.Document.Body.OuterHtml'來跟蹤動態變化。可能有更好的方法來處理它,比如[this](http://stackoverflow.com/questions/8733306/detecting-dom-change-events)。 – Noseratio

+1

完美!我需要做的就是使用_memoryWebBrowser.Document.Body.OuterHtml;而不是_memoryWebBrowser.DocumentText;在我的解決方案!是的,頁面使用AJAX或類似的方式只更新少量的內容。當我說它刷新時,我的意思是隻有一個控件刷新少量內容,整個頁面不會重新加載。 – Ewan

0

您可以捕獲WebBrowser.Navigated事件以在頁面重新加載時得到通知。所以你不需要一個循環。 (我的意思是就緒循環)

只需每30秒瀏覽一次循環中的頁面並在導航事件中,您就可以檢查網站是否已更改。

+0

聽起來不錯,但我不確定該頁面是否實際重新加載。該頁面大多保持靜態,但頁面中有一個控件可以更改內容。我相信他們已經這樣做了,無需重新加載頁面即可顯示新內容。 – Ewan

0

你最好連接DocumentCompleted事件來檢查它的DocumentText屬性!

+0

這將工作在DocumentCompleted但只發生一次。我如何重複檢查差異? – Ewan

+0

在檢查Documentcomplete中的差異後,調用_memoryWebBrowser.Refresh(); – nim

+0

如何使其循環,如果我確實循環,我怎麼知道它不是重新加載頁面?也許我不明白,你有沒有一個例子? – Ewan

0

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; 
     } 
    } 
} 
+0

這工作得很好,我同意使用WebBrowser有一個開銷。儘管這不擔心我,但這種開銷會影響我的Windows窗體。但唯一的小問題是request.GetResponse();在這個解決方案中再次加載整個網頁。它和.Refresh()一樣。在我的解決方案中,我希望避免每30秒做一次。真的,這是我想檢查的內容,因爲它動態變化。 90%的網頁是靜態的,所以我不想每次都重新加載它。有沒有辦法做一個網頁加載,然後只檢查變化的內容? – Ewan

+0

剛剛添加,這是一個很好的例子,但對我來說,答案是使用_memoryWebBrowser.Document.Body.OuterHtml;而不是_memoryWebBrowser.DocumentText;這只是我現有代碼中的1行更改,然後我能夠註釋掉我的_memoryWebBrowser.Refresh();這完成了我的最終目標,因爲我正在加載網頁一次,然後不刷新頁面,我正在檢查動態更改的內容。 WebBrowser開銷不受關注,因爲它只發生一次。循環中的效率更重要,即不使用Refresh或GetResponse()來重新加載。 – Ewan

+0

在你的問題中,你說網站的內容經常變化。這可以被視爲a)某人更改了代碼或者b)您在該網站上擁有AJAX(或類似),並且只是對內容進行了一些更改。所以我想你想每隔30秒拿到整個頁面,並與前一頁進行比較。不是一點點!很高興看到你自己解決了它。 – Pixelmonster