Web浏览器线程似乎没有关闭

时间:2014-05-20 20:30:55

标签: c# javascript multithreading webbrowser-control

我正在使用WebBrowser在网页上呈现javascript来抓取渲染的源代码,但是在多次加载页面后,CPU使用率达到了100%以及线程数。

我假设一旦网页呈现后线程没有正确关闭。我正在尝试打开浏览器,提取源代码,然后关闭浏览器并转到下一页。

我能够获得渲染的页面,但是这个程序在陷入困境之前并没有走得太远。我尝试添加wb.Stop(),但这没有用。记忆似乎不是问题(保持在70%左右)。

这是我的源代码。     使用系统;     使用System.Collections.Generic;     使用System.Linq;     使用System.Text;     使用System.Threading.Tasks;     使用System.Windows.Forms;     使用System.Threading;

namespace Abot.Demo
{
    // Threaded version
    public class HeadlessBrowser
    {
        private static string GeneratedSource { get; set; }
        private static string URL { get; set; }

        public static string GetGeneratedHTML(string url)
        {
            URL = url;

            Thread t = new Thread(new ThreadStart(WebBrowserThread));
            t.SetApartmentState(ApartmentState.STA);
            t.Start();
            t.Join();

            return GeneratedSource;
        }

        private static void WebBrowserThread()
        {
            WebBrowser wb = new WebBrowser();
            wb.Navigate(URL);

            wb.DocumentCompleted +=
                new WebBrowserDocumentCompletedEventHandler(
                    wb_DocumentCompleted);

            while (wb.ReadyState != WebBrowserReadyState.Complete);
                //Application.DoEvents();

            //Added this line, because the final HTML takes a while to show up
            GeneratedSource = wb.Document.Body.InnerHtml;

            wb.Dispose();
            wb.Stop();
        }

        private static void wb_DocumentCompleted(object sender,
            WebBrowserDocumentCompletedEventArgs e)
        {
            WebBrowser wb = (WebBrowser)sender;
            GeneratedSource = wb.Document.Body.InnerHtml;
        }

    }
}

任何建议将不胜感激。

感谢。

1 个答案:

答案 0 :(得分:1)

WebBrowser专门用于从Windows窗体项目中使用。它不是设计用于Windows窗体项目之外的。

除此之外,它还专门设计为使用应用程序循环,它几乎存在于任何桌面GUI应用程序中。你没有这个,这当然会给你带来麻烦,因为浏览器会利用它来实现基于事件的编程风格。

快速了解未来的读者,他们正在阅读本文,并且实际上正在创建一个winforms,WPF或其他已经有消息循环的应用程序。不要应用以下代码。您应该只在应用程序中有一个消息循环。创建几个就是为噩梦设置自己。

由于您没有应用程序循环,您需要创建一个新的应用程序循环,指定一些代码在该应用程序循环中运行,允许它抽取消息,然后在获得结果时将其拆除。

public static string GetGeneratedHTML(string url)
{
    string result = null;
    ThreadStart pumpMessages = () =>
    {
        EventHandler idleHandler = null;
        idleHandler = (s, e) =>
        {
            Application.Idle -= idleHandler;

            WebBrowser wb = new WebBrowser();
            wb.DocumentCompleted += (s2, e2) =>
            {
                result = wb.Document.Body.InnerHtml;
                wb.Dispose();
                Application.Exit();
            };
            wb.Navigate(url);
        };
        Application.Idle += idleHandler;
        Application.Run();
    };
    if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
        pumpMessages();
    else
    {
        Thread t = new Thread(pumpMessages);
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();
    }
    return result;
}