2013-04-10 72 views
1

要收集網頁上的信息,我可以使用WebBrowser.Navigated事件。如何調用WebBrowser導航瀏覽多個網址?

首先,導航到的網址:

WebBrowser wbCourseOverview = new WebBrowser(); 
wbCourseOverview.ScriptErrorsSuppressed = true; 
wbCourseOverview.Navigate(url); 
wbCourseOverview.Navigated += wbCourseOverview_Navigated; 

然後處理網頁時Navigated叫做:

void wbCourseOverview_Navigated(object sender, WebBrowserNavigatedEventArgs e) 
    { 
     //Find the control and invoke "Click" event... 
    } 

困難的部分是當我嘗試去通過URL的字符串數組。

foreach (var u in courseUrls) 
     { 
      WebBrowser wbCourseOverview = new WebBrowser(); 
      wbCourseOverview.ScriptErrorsSuppressed = true; 
      wbCourseOverview.Navigate(u); 

      wbCourseOverview.Navigated += wbCourseOverview_Navigated; 
     } 

這裏,因爲頁面加載需要時間,所以從未達到wbCourseOverview_Navigated

我試着在C#5中使用asyncawait。任務和基於事件的異步模式(EAP)可在here中找到。另一個例子可以在The Task-based Asynchronous Pattern中找到。

問題是WebClient有異步方法,如DownloadDataAsyncDownloadStringAsync。但WebBrowser中沒有NavigateAsync

任何專家都可以給我一些建議嗎?謝謝。


在StackOverflow中有一個帖子(here)。但是,有沒有人知道如何在其答案中實現該strut


再次更新。

another post here in StackOverflow建議,

public static Task WhenDocumentCompleted(this WebBrowser browser) 
{ 
    var tcs = new TaskCompletionSource<bool>(); 
    browser.DocumentCompleted += (s, args) => tcs.SetResult(true); 
    return tcs.Task; 
} 

所以我必須:

foreach (var c in courseBriefs) 
    { 
     wbCourseOverview.Navigate(c.Url); 
     await wbCourseOverview.WhenDocumentCompleted(); 
    } 

它看起來不錯,直到我的網頁瀏覽器訪問的第二個URL。

嘗試在任務完成時將任務轉換爲最終狀態。

我知道我必須作出了foreach循環中一個錯誤。因爲DocumentCompleted事件在循環到第二輪時未被提升。在foreach循環中編寫這個await的正確方法是什麼?

+1

您是否試圖從WebBrowser控件中刮取HTML?如果是這樣,這是一個非常低效的方法,因爲通過加載所有圖像,JavaScript和插件有很多開銷。您可以自己處理HTTP請求,然後在響應中執行一些操作。 – 2013-04-10 18:26:02

+0

如果您閱讀了鏈接的文章,那麼您應該可以使用'Navigate()','Navigated'和'TaskCompletionSource'自己構建'NavigateAsync()'。 – svick 2013-04-10 19:32:53

+0

@CameronTinker,我不僅需要HTML。我想要的是在一些DOM控件上調用Click事件。所以我不會只使用'DownloadStringTaskAsyc'。 – Blaise 2013-04-12 16:30:04

回答

0

而不是使用wbCourseOverview_Navigated使用webBrowser1_DocumentCompleted當拳頭URL加載完成,完成你的工作,並進入下一網址

List<string> urls = new List<string>(); 
    int count = 0; 
    public Form1() 
    { 
     InitializeComponent(); 
     webBrowser1.DocumentCompleted+=new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted); 
    } 
    private void Form1_Load(object sender, EventArgs e) 
    { 
     webBrowser1.Navigate(urls[count++]); 
    } 

    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
    { 
     //Do something 
     webBrowser1.Navigate(urls[count++]); 
    } 
+0

哈!這個答案讓我再次感到愚蠢。爲什麼我必須堅持我的'foreach'循環?!在回答問題之前,我會等待更多的答案,只是爲了看看是否有人向我們提供了一些「異步等待」解決方案,因爲我真的很想知道。 但是,謝謝IRSOG的快速回復。 – Blaise 2013-04-10 17:51:22

+0

@Blaise:有一個用於.NET的WebBrowser類的Async/Await實現的方法:http://stackoverflow.com/questions/8610197/async-await-implementation-of-webbrowser-class-for-net也檢查它 – KF2 2013-04-10 18:06:42

+0

是的,我已經爲該帖子主演過。但是你有沒有想法如何實現這個支柱? – Blaise 2013-04-10 18:08:23

4

有一個在StackOverflow上(在這裏)一職。但是,有沒有人知道如何在其答案中實現該支撐?

好的,所以你想要一些代碼與awaiter。我做了兩段代碼。 第一個使用TPL的內置awaiter:

public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      ProcessUrlsAsync(new[] { "http://google.com", "http://microsoft.com", "http://yahoo.com" }) 
       .Start(); 
     } 

     private Task ProcessUrlsAsync(string[] urls) 
     { 
      return new Task(() => 
      { 
       foreach (string url in urls) 
       { 
        TaskAwaiter<string> awaiter = ProcessUrlAsync(url); 
        // or the next line, in case we use method * 
        // TaskAwaiter<string> awaiter = ProcessUrlAsync(url).GetAwaiter();      
        string result = awaiter.GetResult(); 

        MessageBox.Show(result); 
       } 
      }); 
     }   

     // Awaiter inside 
     private TaskAwaiter<string> ProcessUrlAsync(string url) 
     { 
      TaskCompletionSource<string> taskCompletionSource = new TaskCompletionSource<string>(); 
      var handler = new WebBrowserDocumentCompletedEventHandler((s, e) => 
      { 
       // TODO: put custom processing of document right here 
       taskCompletionSource.SetResult(e.Url + ": " + webBrowser1.Document.Title); 
      }); 
      webBrowser1.DocumentCompleted += handler; 
      taskCompletionSource.Task.ContinueWith(s => { webBrowser1.DocumentCompleted -= handler; }); 

      webBrowser1.Navigate(url); 
      return taskCompletionSource.Task.GetAwaiter(); 
     } 

     // (*) Task<string> instead of Awaiter 
     //private Task<string> ProcessUrlAsync(string url) 
     //{ 
     // TaskCompletionSource<string> taskCompletionSource = new TaskCompletionSource<string>(); 
     // var handler = new WebBrowserDocumentCompletedEventHandler((s, e) => 
     // { 
     //  taskCompletionSource.SetResult(e.Url + ": " + webBrowser1.Document.Title); 
     // }); 
     // webBrowser1.DocumentCompleted += handler; 
     // taskCompletionSource.Task.ContinueWith(s => { webBrowser1.DocumentCompleted -= handler; }); 

     // webBrowser1.Navigate(url); 
     // return taskCompletionSource.Task; 
     //} 

而接下來的樣品中含有awaiter結構埃裏克利珀在談論here的樣本實現。

public partial class Form1 : Form 
    { 
     public struct WebBrowserAwaiter 
     { 
      private readonly WebBrowser _webBrowser; 
      private readonly string _url; 

      private readonly TaskAwaiter<string> _innerAwaiter; 

      public bool IsCompleted 
      { 
       get 
       { 
        return _innerAwaiter.IsCompleted; 
       } 
      } 

      public WebBrowserAwaiter(WebBrowser webBrowser, string url) 
      { 
       _url = url; 
       _webBrowser = webBrowser; 
       _innerAwaiter = ProcessUrlAwaitable(_webBrowser, url); 
      } 

      public string GetResult() 
      { 
       return _innerAwaiter.GetResult(); 

      } 

      public void OnCompleted(Action continuation) 
      { 
       _innerAwaiter.OnCompleted(continuation); 
      } 

      private TaskAwaiter<string> ProcessUrlAwaitable(WebBrowser webBrowser, string url) 
      { 
       TaskCompletionSource<string> taskCompletionSource = new TaskCompletionSource<string>(); 
       var handler = new WebBrowserDocumentCompletedEventHandler((s, e) => 
       { 
        // TODO: put custom processing of document here 
        taskCompletionSource.SetResult(e.Url + ": " + webBrowser.Document.Title); 
       }); 
       webBrowser.DocumentCompleted += handler; 
       taskCompletionSource.Task.ContinueWith(s => { webBrowser.DocumentCompleted -= handler; }); 

       webBrowser.Navigate(url); 
       return taskCompletionSource.Task.GetAwaiter(); 
      } 
     } 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      ProcessUrlsAsync(new[] { "http://google.com", "http://microsoft.com", "http://yahoo.com" }) 
       .Start(); 
     } 

     private Task ProcessUrlsAsync(string[] urls) 
     { 
      return new Task(() => 
      { 
       foreach (string url in urls) 
       { 
        var awaiter = new WebBrowserAwaiter(webBrowser1, url); 
        string result = awaiter.GetResult(); 

        MessageBox.Show(result); 
       } 
      }); 
     } 
    } 
     } 

希望這會有所幫助。

+0

感謝您的幫助。看來你在這個解決方案中使用'await'或'async'關鍵字。你有什麼理由避免它們?在這種情況下,它們不易實現嗎? – Blaise 2013-04-12 16:45:28

+0

這個答案如此詳細。現在我至少有一個工作的例子。謝謝。 – Blaise 2013-04-12 16:54:12