问题范围:
我正在编写一个应用程序来保存从Bing和Google搜索中检索到的HTML。我知道有些类可以使用this example等流来执行Web请求,但由于Google和Bing都使用Javascript和Ajax将结果呈现到HTML中,因此我无法简单地读取流并使用get我需要的结果。
对此的解决方案是使用WebBrowser类并导航到我想要的URL,以便浏览器本身将处理所有Javascript和Ajax脚本执行。
多线程:
为了提高效率,我有相同的表单应用程序为每个服务启动一个线程(一个用于Bing,一个用于Google)。
问题:
由于我需要WebBrowser,我已经为每个线程实例化了一个(此时为2)。据微软称,有一个known bug that prevents the DocumentCompleted event from firing if the WebBrowser is not visible and is not added to a visible form aswell
(更多信息,follow this link)。
真实问题:
主要问题是,浏览器的DocumentCompleted
事件永远不会触发。从不。
我为永远不会收到回调的DocumentCompleted
事件写了一个合适的处理程序。为了处理触发Browser事件所需的等待,我实现了一个具有高超时(5分钟)的AutoResetEvent,如果它在5分钟后没有触发我需要的事件,它将处理webbrowser线程。 / p>
目前,我已经创建了浏览器并将其添加到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总是超时并且我没有响应来自浏览器。
先谢谢,对不起,
答案 0 :(得分:2)
虽然这看起来很奇怪,但这是我的尝试。
var tasks = new Task<string>[]
{
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<string> _tcs;
ApplicationContext _ctx;
public Task<string> Download(string url)
{
_tcs = new TaskCompletionSource<string>();
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();
}
}