我正在使用基于WebBrowser的webscraper工作几天。在使用Threads和DocumentCompleted事件的几个原型之后,我决定尝试看看我是否可以创建一个简单易懂的Webscraper。
目标是创建一个不涉及实际Thread对象的Webscraper。我想让它按顺序步骤工作(即转到网址,执行操作,转到其他网址等等。)
这是我到目前为止所得到的:
public static class Webscraper
{
private static WebBrowser _wb;
public static string URL;
//WebBrowser objects have to run in Single Thread Appartment for some reason.
[STAThread]
public static void Init_Browser()
{
_wb = new WebBrowser();
}
public static void Navigate_And_Wait(string url)
{
//Navigate to a specific url.
_wb.Navigate(url);
//Wait till the url is loaded.
while (_wb.IsBusy) ;
//Loop until current url == target url. (In case a website loads urls in steps)
while (!_wb.Url.ToString().Contains(url))
{
//Wait till next url is loaded
while (_wb.IsBusy) ;
}
//Place URL
URL = _wb.Url.ToString();
}
}
我是一名新手程序员,但我认为这是非常简单的代码。 这就是为什么我讨厌由于某种原因程序在这段代码中抛出NullReferenceException的事实:
_wb.Url.ToString().Contains(url)
我刚刚调用_wb.Navigate()方法,因此NullReference不能在_wb对象本身。所以我唯一能想到的是_wb.Url对象为null。但while _wb.IsBusy()循环应该阻止它。
那是怎么回事?如何解决?
答案 0 :(得分:4)
UI线程上的忙等待(while (_wb.IsBusy) ;
)不太可取。如果您使用.Net 4.5的新功能async/await,您可以获得类似的效果(即转到网址,执行操作,转到其他网址等等。)
public static class SOExtensions
{
public static Task NavigateAsync(this WebBrowser wb, string url)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
WebBrowserDocumentCompletedEventHandler completedEvent = null;
completedEvent = (sender, e) =>
{
wb.DocumentCompleted -= completedEvent;
tcs.SetResult(null);
};
wb.DocumentCompleted += completedEvent;
wb.ScriptErrorsSuppressed = true;
wb.Navigate(url);
return tcs.Task;
}
}
async void ProcessButtonClick()
{
await webBrowser1.NavigateAsync("http://www.stackoverflow.com");
MessageBox.Show(webBrowser1.DocumentTitle);
await webBrowser1.NavigateAsync("http://www.google.com");
MessageBox.Show(webBrowser1.DocumentTitle);
}