我应该如何使用multithreading正确调用WebBrowser?

问题范围:

我正在编写一个应用程序来保存从Bing和Google搜索中检索到的HTML。 我知道有一些类可以使用流来执行Web请求,例如这个例子 ,但是由于Google和Bing都使用Javascript和Ajax将结果呈现到HTML中,所以我无法简单地读取流并使用获取结果我需要。

对此的解决方案是使用WebBrowser类并导航到我想要的URL,以便浏览器本身将处理所有Javascript和Ajax脚本执行。

multithreading:

为了提高效率,我使用相同的表单应用程序为每个服务启动一个线程(一个用于Bing,一个用于Google)。

问题:

由于我需要WebBrowser,我已经为每个线程实例化了一个(此时为2)。 根据Microsoft的说法, known bug that prevents the DocumentCompleted event from firing if the WebBrowser is not visible and is not added to a visible form aswell ,则存在一个known bug that prevents the DocumentCompleted event from firing if the WebBrowser is not visible and is not added to a visible form aswell (有关更多信息,请点击此链接 )。

真正的问题:

主要问题是,浏览器的DocumentCompleted事件永远不会触发。 决不。

我为DocumentCompleted事件编写了一个适当的处理程序,它永远不会得到回调。 为了处理触发Browser事件所需的等待,我实现了一个具有高超时(5分钟)的AutoResetEvent ,如果它在5分钟后没有触发我需要的事件,它将处理webbrowser线程。

目前,我已经创建了浏览器并将其添加到WindowsForm中,两者都可见,并且事件仍未触发。

一些代码:

  // Creating Browser Instance browser = new WebBrowser (); // Setting up Custom Handler to "Document Completed" Event browser.DocumentCompleted += DocumentCompletedEvent; // Setting Up Random Form genericForm = new Form(); genericForm.Width = 200; genericForm.Height = 200; genericForm.Controls.Add (browser); browser.Visible = true; 

至于导航我有以下(浏览器的方法):

  public void NavigateTo (string url) { CompletedNavigation = false; if (browser.ReadyState == WebBrowserReadyState.Loading) return; genericForm.Show (); // Shows the form so that it is visible at the time the browser navigates browser.Navigate (url); } 

而且,对于导航的调用我有这个:

  // Loading URL browser.NavigateTo(URL); // Waiting for Our Event To Fire if (_event.WaitOne (_timeout)) { // Success } { // Error / Timeout From the AutoResetEvent } 

TL:DR:

我的WebBrowser被实例化为另一个STAThread,添加到表单中,两者都可见并在浏览器导航触发时显示,但是来自浏览器的DocumentCompleted事件永远不会被触发,因此AutoResetEvent总是超时并且我没有来自浏览器的响应。

在此先感谢,并为长篇文章感到抱歉

虽然这看起来很奇怪,但这是我的尝试。

 var tasks = new Task[] { new MyDownloader().Download("http://www.stackoverflow.com"), new MyDownloader().Download("http://www.google.com") }; Task.WaitAll(tasks); Console.WriteLine(tasks[0].Result); Console.WriteLine(tasks[1].Result); 

 public class MyDownloader { WebBrowser _wb; TaskCompletionSource _tcs; ApplicationContext _ctx; public Task Download(string url) { _tcs = new TaskCompletionSource(); var t = new Thread(()=> { _wb = new WebBrowser(); _wb.ScriptErrorsSuppressed = true; _wb.DocumentCompleted += _wb_DocumentCompleted; _wb.Navigate(url); _ctx = new ApplicationContext(); Application.Run(_ctx); }); t.SetApartmentState(ApartmentState.STA); t.Start(); return _tcs.Task; } void _wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { //_tcs.TrySetResult(_wb.DocumentText); _tcs.TrySetResult(_wb.DocumentTitle); _ctx.ExitThread(); } }