-1

几天来,我正在研究基于 WebBrowser 的网络爬虫。在使用了几个使用 Threads 和 DocumentCompleted 事件的原型之后,我决定尝试看看我是否可以制作一个简单、易于理解的 Webscraper。

目标是创建一个不涉及实际 Thread 对象的 Webscraper。我希望它按顺序工作(即转到 url、执行操作、转到其他 url 等)。

这是我到目前为止得到的:

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 对象是空的。但是 while _wb.IsBusy() 循环应该可以防止这种情况。

那么发生了什么,我该如何解决?

4

1 回答 1

4

UI 线程上的忙碌等待 ( while (_wb.IsBusy) ;) 不太可取。如果您使用 .Net 4.5 的新功能async/await,您可以获得类似的效果(即转到 url、执行操作、转到其他 url 等) 。

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);
}
于 2013-04-25T06:55:40.177 回答