如何调用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
有像DownloadDataAsync
和DownloadStringAsync
这样的异步方法。 但是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++]); }