如何调用WebBrowser导航来浏览一些url?

要收集网页上的信息,我可以使用WebBrowser.Navigated事件。

首先,导航到url:

 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永远不会达到wbCourseOverview_Navigated

我试图在C#5中使用async await 。 任务和基于事件的异步模式(EAP)可在此处找到。 另一个例子可以在基于任务的异步模式中找到 。

问题是WebClient有像DownloadDataAsyncDownloadStringAsync这样的异步方法。 但是WebBrowser没有NavigateAsync

有专家可以给我一些建议吗? 谢谢。


StackOverflow中有一篇文章( 这里 )。 但是,有谁知道如何在答案中实现这个strut


再次更新。

建议在StackOverflow中的另一篇文章中 ,

 public static Task WhenDocumentCompleted(this WebBrowser browser) { var tcs = new TaskCompletionSource(); 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的正确方法是什么?

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 awaiter = ProcessUrlAsync(url); // or the next line, in case we use method * // TaskAwaiter awaiter = ProcessUrlAsync(url).GetAwaiter(); string result = awaiter.GetResult(); MessageBox.Show(result); } }); } // Awaiter inside private TaskAwaiter ProcessUrlAsync(string url) { TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); 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 instead of Awaiter //private Task ProcessUrlAsync(string url) //{ // TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); // 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; //} 

下一个示例包含Eric Lippert在这里讨论的awaiter结构的示例实现。

 public partial class Form1 : Form { public struct WebBrowserAwaiter { private readonly WebBrowser _webBrowser; private readonly string _url; private readonly TaskAwaiter _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 ProcessUrlAwaitable(WebBrowser webBrowser, string url) { TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); 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); } }); } } } 

希望这可以帮助。

而不是使用wbCourseOverview_Navigated使用webBrowser1_DocumentCompleted当第一次URL加载完成你的工作并转到下一个url

 List urls = new List(); 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++]); }