首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用CefSharp.Offscreen检索需要Javascript呈现的网页

使用CefSharp.Offscreen检索需要Javascript呈现的网页
EN

Stack Overflow用户
提问于 2016-02-18 09:45:40
回答 2查看 17.7K关注 0票数 7

我有一个希望是简单的任务,但它将需要一个精通CefSharp的人来解决。

我有一个url,我想要从中检索HTML。问题是这个特定的url实际上并不会在GET上分发页面。取而代之的是,它将一堆Javascript推送到浏览器,然后浏览器执行并生成实际呈现的页面。这意味着涉及HttpWebRequestHttpWebResponse的常用方法将不起作用。

我已经研究了许多不同的"headless“选项,我认为最能满足我需求的是CefSharp.Offscreen。但是我不知道这东西是怎么工作的。我看到有几个事件可以订阅,还有一些配置选项,但我不需要嵌入式浏览器之类的东西。

我真正需要的是这样做的一种方法(伪代码):

代码语言:javascript
运行
复制
string html = CefSharp.Get(url);

如果需要等待Javascript执行并生成呈现的页面,那么订阅事件没有问题。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-02-18 11:38:21

如果你找不到无头版的Chromium浏览器,你可以试试node.js和jsdom。一旦节点启动并运行,就很容易安装和使用。你可以在Github README上看到一些简单的例子,他们拉下一个URL,运行所有的javascript,包括任何自定义的javascript代码(例如: jQuery位来计算某些类型的元素),然后你在内存中有了你想做的事情。您可以只执行$('body').html()并获得一个字符串,就像您的伪代码中一样。(这甚至适用于生成SVG图形之类的东西,因为那只是更多的XML树节点。)

如果您需要将其作为需要分发的大型C#应用程序的一部分,那么使用CefSharp.Offscreen的想法听起来很合理。一种方法可能是先在CefSharp.WinForms或CefSharp.WPF上运行,这样您就可以从字面上看到内容,然后在所有这些都运行时再尝试CefSharp.Offscreen。您甚至可以在屏幕浏览器中运行一些JavaScript来下载body.innerHTML,并将其作为字符串返回到C#端,然后再变得无用。如果这能行得通,剩下的事情应该会很容易。

也许可以从CefSharp.MinimalExample开始编译,然后根据需要对其进行调整。您需要能够在C#代码中设置webBrowser.Address,并且需要知道页面何时加载,然后需要调用webBrowser.EvaluateScriptAsync(".. JS代码..")使用您的JavaScript代码(以字符串形式),它将执行所述的操作(以字符串形式返回bodyElement.innerHTML )。

票数 4
EN

Stack Overflow用户

发布于 2018-08-15 04:14:58

我知道我正在做一些考古工作来复活一个2yo的帖子,但是一个详细的答案可能对其他人有用。

所以,是的,Cefsharp.Offscreen适合这项任务。

下面是一个处理所有浏览器活动的类。

代码语言:javascript
运行
复制
using System;
using System.IO;
using System.Threading;
using CefSharp;
using CefSharp.OffScreen;

namespace [whatever]
{
    public class Browser
    {

        /// <summary>
        /// The browser page
        /// </summary>
        public ChromiumWebBrowser Page { get; private set; }
        /// <summary>
        /// The request context
        /// </summary>
        public RequestContext RequestContext { get; private set; }

        // chromium does not manage timeouts, so we'll implement one
        private ManualResetEvent manualResetEvent = new ManualResetEvent(false);

        public Browser()
        {
            var settings = new CefSettings()
            {
                //By default CefSharp will use an in-memory cache, you need to     specify a Cache Folder to persist data
                CachePath =     Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache"),
            };

            //Autoshutdown when closing
            CefSharpSettings.ShutdownOnExit = true;

            //Perform dependency check to make sure all relevant resources are in our     output directory.
            Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);

            RequestContext = new RequestContext();
            Page = new ChromiumWebBrowser("", null, RequestContext);
            PageInitialize();
        }

        /// <summary>
        /// Open the given url
        /// </summary>
        /// <param name="url">the url</param>
        /// <returns></returns>
        public void OpenUrl(string url)
        {
            try
            {
                Page.LoadingStateChanged += PageLoadingStateChanged;
                if (Page.IsBrowserInitialized)
                {
                    Page.Load(url);

                    //create a 60 sec timeout 
                    bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(60));
                    manualResetEvent.Reset();

                    //As the request may actually get an answer, we'll force stop when the timeout is passed
                    if (!isSignalled)
                    {
                        Page.Stop();
                    }
                }
            }
            catch (ObjectDisposedException)
            {
                //happens on the manualResetEvent.Reset(); when a cancelation token has disposed the context
            }
            Page.LoadingStateChanged -= PageLoadingStateChanged;
        }

        /// <summary>
        /// Manage the IsLoading parameter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PageLoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
        {
            // Check to see if loading is complete - this event is called twice, one when loading starts
            // second time when it's finished
            if (!e.IsLoading)
            {
                manualResetEvent.Set();
            }
        }

        /// <summary>
        /// Wait until page initialization
        /// </summary>
        private void PageInitialize()
        {
            SpinWait.SpinUntil(() => Page.IsBrowserInitialized);
        }
    }
}

现在,在我的应用程序中,我只需要执行以下操作:

代码语言:javascript
运行
复制
public MainWindow()
{
    InitializeComponent();
    _browser = new Browser();
}

private async void GetGoogleSource()
{
    _browser.OpenUrl("http://icanhazip.com/");
    string source = await _browser.Page.GetSourceAsync();
}

这是我得到的字符串

"<html><head></head><body><pre style=\"word-wrap: break-word; white-space: pre-wrap;\">NotGonnaGiveYouMyIP:)\n</pre></body></html>"

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35471261

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档