【问题标题】:Web scraping using WebBrowser in a class library在类库中使用 WebBrowser 进行 Web 抓取
【发布时间】:2016-10-15 07:17:55
【问题描述】:

我需要在类库中创建一个方法来获取 URL 的内容(可能由 JavaScript 动态填充)。

我一无所知,但是整天搜索这就是我想出的:(大部分代码来自here

using System;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Forms;

public static class WebScraper
{
    [STAThread]
    public async static Task<string> LoadDynamicPage(string url, CancellationToken token)
    {
        using (WebBrowser webBrowser = new WebBrowser())
        {
            // Navigate and await DocumentCompleted
            var tcs = new TaskCompletionSource<bool>();
            WebBrowserDocumentCompletedEventHandler onDocumentComplete = (s, arg) => tcs.TrySetResult(true);

            using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
            {
                webBrowser.DocumentCompleted += onDocumentComplete;
                try
                {
                    webBrowser.Navigate(url);
                    await tcs.Task; // wait for DocumentCompleted
                }
                finally
                {
                    webBrowser.DocumentCompleted -= onDocumentComplete;
                }
            }

            // get the root element
            var documentElement = webBrowser.Document.GetElementsByTagName("html")[0];

            // poll the current HTML for changes asynchronosly
            var html = documentElement.OuterHtml;
            while (true)
            {
                // wait asynchronously, this will throw if cancellation requested
                await Task.Delay(500, token);

                // continue polling if the WebBrowser is still busy
                if (webBrowser.IsBusy)
                    continue;

                var htmlNow = documentElement.OuterHtml;
                if (html == htmlNow)
                    break; // no changes detected, end the poll loop

                html = htmlNow;
            }

            // consider the page fully rendered 
            token.ThrowIfCancellationRequested();
            return html;
        }
    }
}

它当前抛出此错误

ActiveX 控件 '8856f961-340a-11d0-a96b-00c04fd705a2' 不能 实例化,因为当前线程不在单线程中 公寓。

我接近了吗?上面有解决办法吗?

或者如果我偏离了轨道,是否有现成的解决方案可以使用 .NET(可以从类库调用)获取动态 Web 内容?

【问题讨论】:

    标签: c# .net web-scraping


    【解决方案1】:

    这是我在 Web 应用程序中测试并正常工作的内容。

    它在另一个线程中使用WebBrowser 控件并返回一个Task&lt;string&gt;,包含在浏览器内容完全加载时完成:

    using System;
    using System.Threading.Tasks;
    using System.Threading;
    using System.Windows.Forms;
    public class BrowserBasedWebScraper
    {
        public static Task<string> LoadUrl(string url)
        {
            var tcs = new TaskCompletionSource<string>();
            Thread thread = new Thread(() => {
                try {
                    Func<string> f = () => {
                        using (WebBrowser browser = new WebBrowser())
                        {
                            browser.ScriptErrorsSuppressed = true;
                            browser.Navigate(url);
                            while (browser.ReadyState != WebBrowserReadyState.Complete)
                            {
                                System.Windows.Forms.Application.DoEvents();
                            }
                            return browser.DocumentText;
                        }
                    };
                    tcs.SetResult(f());
                }
                catch (Exception e) {
                    tcs.SetException(e);
                }
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
            return tcs.Task;
        }
    }
    

    【讨论】:

    • 谢谢!它不适用于google.com/#q=where+am+i,但它可能足以满足我现在的需要
    • 不客气。关于另一个问题,我想这是因为WebBrowser 控件默认不使用最新版本的浏览器。您可以强制它使用最新版本。我已经为 Windows 窗体应用程序申请了 the solution
    • System.Windows.Forms.Application.DoEvents 似乎不是关键。问题仍然存在,尤其是在繁重的 Ajax 请求上,这可能意味着解决方案可能在 Ajax 请求代码方面(请参阅codesave.wordpress.com/2013/09/25/…)。
    猜你喜欢
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 2018-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多