1

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

首先,导航到网址:

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...
    }

当我尝试遍历一个字符串数组时,困难的部分就来了。

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

            wbCourseOverview.Navigated += wbCourseOverview_Navigated;
        }

在这里,因为页面加载需要时间,wbCourseOverview_Navigated所以永远不会到达。

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

问题是WebClient有 async 方法,比如DownloadDataAsyncand DownloadStringAsync。但是里面没有NavigateAsyncWebBrowser

有哪位高手能给我一些建议吗?谢谢你。


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


再次更新。

在 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();
    }

在我的网络浏览器访问第二个网址之前,它看起来不错。

尝试在任务已完成时将其转换为最终状态。

我知道我一定在foreach循环内犯了一个错误。因为DocumentCompleted事件循环到第二轮时还没有引发。awaitforeach循环中写这个的正确方法是什么?

4

2 回答 2

4

StackOverflow 中有一篇文章(这里)。但是,有谁知道如何在其答案中实现该支柱?

好的,所以你想要一些带有等待者的代码。我做了两段代码。第一个使用 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;
        //}

下一个示例包含 Eric Lippert 在这里谈到的 awaiter struct 的示例实现。

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);
                }
            });
        }
    }   
        }

希望这可以帮助。

于 2013-04-10T21:06:04.023 回答
0

而不是在第一个 URL 加载完成时使用wbCourseOverview_NavigatedusewebBrowser1_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++]);
    }
于 2013-04-10T17:40:12.790 回答