Cef.Initialize can only be called once per process

文章介绍了CefSharp库在.NET环境中使用时遇到的只能初始化一次的限制,并提供了解决方案,即在静态构造函数中执行初始化。同时,展示了如何使用ChromiumWebBrowser进行网页交互,包括模拟登录、获取验证码图片和处理cookies。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常情况:
Cef.Initialize can only be called once per process. This is a limitation of the underlying CEF/Chromium framework.
You can change many (not all) settings at runtime through RequestContext.SetPreference.
See https://github.com/cefsharp/CefSharp/wiki/General-Usage#request-context-browser-isolation
Use Cef.IsInitialized to check if Cef.Initialize has already been called to avoid this exception.
If you are seeing this unexpectedly then you are likely calling Cef.Initialize after
you’ve created an instance of ChromiumWebBrowser, it must be called before the first instance is created.
翻译:每个进程只能调用一次Cef.Initialize。这是基础CEF/Chromium框架的限制。您可以在运行时通过RequestContext.SetPreference更改许多(而不是全部)设置。请参阅https://github.com/cefsharp/CefSharp/wiki/General-Usage#request-上下文浏览器隔离使用Cef.IsInitialize检查是否已调用Cef.Initialize以避免此异常。如果你意外地看到了这一点,那么你很可能正在调用Cef.Initialize。在创建ChromiumWebBrowser的实例后,必须在创建第一个实例之前调用它。

下面这段代码只能在同一个进程中,执行一次;

   var cefSettingOp = new CefSettings()
            {
                CookieableSchemesExcludeDefaults = false,
                PersistSessionCookies = true,
                //WindowlessRenderingEnabled = true,
            };
#if DEBUG
            
            //http://localhost:9080  本地调试窗口
            cefSettingOp.RemoteDebuggingPort = 9080;
#endif
            Cef.Initialize(cefSettingOp, performDependencyCheck: true, browserProcessHandler: null);

主要将上面代码在静态构造函数执行一次即可;

解决:

using CefSharp.OffScreen;
using CefSharp;
using System.Text.RegularExpressions;
using System.Drawing;
using CefSharp.Handler;

namespace Web_rongmeiti_sys.PublishToRongMeiTi
{
    /// <summary>
    /// 登录处理
    /// </summary>
    /// 创建时间:2023-5-23 10:23:54。创建人:xxx
    public class LoginHandler
    {
        static LoginHandler()
        {
            /* 异常情况:
            Cef.Initialize can only be called once per process. This is a limitation of the underlying CEF/Chromium framework.
            You can change many (not all) settings at runtime through RequestContext.SetPreference. 
            See https://github.com/cefsharp/CefSharp/wiki/General-Usage#request-context-browser-isolation 
            Use Cef.IsInitialized to check if Cef.Initialize has already been called to avoid this exception. 
            If you are seeing this unexpectedly then you are likely calling Cef.Initialize after
            you've created an instance of ChromiumWebBrowser, it must be called before the first instance is created.
            */
            //初始化Cef.Initialize在同一线程中,只准执行一次,否则报错
            var cefSettingOp = new CefSettings()
            {
                CookieableSchemesExcludeDefaults = false,
                PersistSessionCookies = true,
                //WindowlessRenderingEnabled = true,
            };
#if DEBUG
            
            //http://localhost:9080  本地调试窗口
            cefSettingOp.RemoteDebuggingPort = 9080;
#endif
            Cef.Initialize(cefSettingOp, performDependencyCheck: true, browserProcessHandler: null);

        }

        /// <summary>
        ///  验证码获取,模拟登录
        /// </summary>
        /// 创建时间:2023-6-21 16:16:43, 
        public static Result LoginCall(string account, string password)
        {

            cookieSb.Clear();

            //1.账号密码登录,
            //2.验证码图形识别
            //string url = "https://gk.abm.kpc/login.html";
            string url = MyConfigReader.GetConfigValue("iam_login_url");

            //Result<string> result = HttpHandler.GetPageAsync(url, null).Result;

            解析html
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            //HtmlAgilityPack
            //HtmlWeb web = new HtmlWeb();
            //var doc = web.LoadFromWebAsync(url).Result;
            //var html = doc.ParsedText;
            //var nodes = doc.DocumentNode.SelectNodes("//div[@id='news_list']/div/div[2]/h2/a");
  
            ChromiumWebBrowser webBrowser = new ChromiumWebBrowser(url)
            {
                RequestHandler = new MyRequestHandler() { Cnpc_account = account }
                //ResourceRequestHandlerFactory = new ResourceRequestHandler3()
            };

            webBrowser.FrameLoadEnd += WebBrowser_FrameLoadEnd;
            //webBrowser.AddressChanged += WebBrowser_AddressChanged;

            //等待内容完成加载
            webBrowser.WaitForInitialLoadAsync().Wait();
            //Task.Delay(500).Wait();

            //tab切换到账号登录
            //$("li[data-name=accountLogin]").click();
            var taskTabJs = webBrowser.GetMainFrame().EvaluateScriptAsync("$(\"li[data-name=accountLogin]\").click();");
            taskTabJs.Wait();
            Task.Delay(500).Wait();

            //点击触发生成验证码图片,执行页面中的js函数loadverifyimg()
            //webBrowser.GetMainFrame().EvaluateScriptAsync("loadverifyimg()").Wait();

            //获取验证码图片url
            //$("img.checkImage").attr("src")
            var jsResponse = webBrowser.GetMainFrame().EvaluateScriptAsync("$(\"img.checkImage\").attr(\"src\")");
            jsResponse.Wait();

            JavascriptResponse javascriptResponse = jsResponse.Result;
            if (!javascriptResponse.Success || javascriptResponse.Result is null || string.IsNullOrWhiteSpace(javascriptResponse.Result.ToString()))
            {
                LogHelpter.AddLog("没有获取到验证码图片url", null, "jsError");
                return new Result("登录失败");
            }

            获取页面html
            //string html9 = webBrowser.GetSourceAsync().Result;

            //验证码图片url
            string imgVerifyUrl = javascriptResponse.Result.ToString();

            //域名
            string baseUrl = Regex.Match(url, "(https://|http://)[A-Za-z0-9.]+/").Value;
            string imgUrl = baseUrl + imgVerifyUrl;

            //下载验证码图片到本地保存
            HttpClient client = new HttpClient();
            var taskImg = client.GetByteArrayAsync(imgUrl);
            taskImg.Wait();
            string imgDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "imgVerify", DateTime.Now.ToString("yyyyMM"));
            if (!System.IO.Directory.Exists(imgDir))
            {
                System.IO.Directory.CreateDirectory(imgDir);
            }

			//验证码图片
            string fileNameImg = Path.Combine(imgDir, DateTime.Now.Ticks + ".jpg"); 
            byte[] imageBytes = taskImg.Result;

            //保存验证码图片到本地.jpg
            using (MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length))
            {
                ms.Write(imageBytes, 0, imageBytes.Length);
                var img = Image.FromStream(ms, true);
                img.Save(fileNameImg, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
 
            模拟登录
            //string account = MyConfigReader.GetConfigValue("iam_login_account");
            //string password = MyConfigReader.GetConfigValue("iam_login_password");

            //账号、密码、验证码赋值js; 调用登录js方法
            string jsLoginWork = $"$(\"#cnpc-input-userName\").val(\"{account}\");"
                        + $"$(\"#cnpc-input-pwd\").val(\"{password}\");"
                        + $"$(\".verifyCode\").val(\"{result}\");"
                        + "userNameLogin();";

            var jsLogin = webBrowser.GetMainFrame().EvaluateScriptAsync(jsLoginWork);
            jsLogin.Wait();

            JavascriptResponse jsLoginResponse = jsLogin.Result;
            if (!jsLoginResponse.Success)
            {
                LogHelpter.AddLog("登录账号、密码赋值给输入框,登录模拟点击js", null, "jsError");
                return new Result("登录失败");
            }

            //等待url变化后,加载的新页面,登录成功后进入https://gk.abm.kpc/index.html
            var navHome = webBrowser.WaitForNavigationAsync();
            navHome.Wait();

            //等待内容完成加载
            webBrowser.WaitForInitialLoadAsync().Wait();

            查看登录后的代码
            //string html25 = webBrowser.GetSourceAsync().Result;

    
            webBrowser.Load(MyConfigReader.GetConfigValue("rongmeiti_url"));

            //var jsLoginPfEip = webBrowser.GetMainFrame().EvaluateScriptAsync("window.location.href=\"https://gk.abm.kpc/\";");
            //jsLoginPfEip.Wait();

            //等待url变化后,加载的新页面,登录成功后进入https://gk.abm.kpc/index.html
            var cnHome = webBrowser.WaitForNavigationAsync(timeout: TimeSpan.FromSeconds(30));
            cnHome.Wait();

            //等待内容完成加载
            webBrowser.WaitForInitialLoadAsync().Wait();

            //检察是否成功写了cookie文件,没有成功则一直阻塞线程,2023-6-27 16:16:28
            int check_count = 0;
            while (true)
            {
                if (check_count > 10)
                {
                    LogHelpter.AddLog("一直获取不到cookie,处理异常", null, "identityCookie_while_error");
                    return new Result("登录失败");
                }
                string? identityCookie = AuthCookieHelpter.GetIdentityCookie(account);
                if (!string.IsNullOrWhiteSpace(identityCookie))
                {
                    LogHelpter.AddLog("成功写了cookie文件,account=" + account, null, "identityCookie_while");
                    break;
                }
                LogHelpter.AddLog("检察是否成功写了cookie文件...", null, "identityCookie_while");
                check_count++;
                Thread.Sleep(1000);
            }

            return new Result("登录成功", 200);
        }

        private static void WebBrowser_AddressChanged(object? sender, AddressChangedEventArgs e)
        {
            LogHelpter.AddLog(e.Address, null, "AddressChanged");
        }

        public static System.Text.StringBuilder cookieSb = new System.Text.StringBuilder();

        private static void WebBrowser_FrameLoadEnd(object? sender, FrameLoadEndEventArgs e)
        {
            //获取谁在调用,cnpc账号
            ChromiumWebBrowser webBrowser = sender as ChromiumWebBrowser;
            var myRequestHandler = webBrowser.RequestHandler as MyRequestHandler;
            string cnpc_account = myRequestHandler.Cnpc_account;

            LogHelpter.AddLog(e.Url + " 状态=" + e.HttpStatusCode, null, "Log_FrameLoadEnd");

		    //cookie捕获
            var cookieManager = Cef.GetGlobalCookieManager();
            CookieVisitorHandle visitor = new CookieVisitorHandle();
            visitor.OnCookie = cookie =>
            {
                string url = cookie.Domain + cookie.Path;
                LogHelpter.AddLog($"path={url},{cookie.Name}={cookie.Value}", null, "getCookie");

                //pf.eip.cnpc/api,.AspNetCore.CookiesC1
                //pf.eip.cnpc/api,.AspNetCore.CookiesC2                 
                if (url == "pf.eip.cnpc/api" && cookie.Name == ".AspNetCore.CookiesC1")
                {
                    cookieSb.Append(cookie.Name + "=" + cookie.Value + ";");
                    if (cookie.Value.Length > 0)
                    {
                        LogHelpter.AddLog("登录成功", null, "FrameLoadEnd");
                    }
                }
                if (url == "pf.eip.cnpc/api" && cookie.Name == ".AspNetCore.CookiesC2")
                {
                    cookieSb.Append(cookie.Name + "=" + cookie.Value + ";");

                    //保存cookie到本地文件
                    AuthCookieHelpter.SaveCookie(cnpc_account, cookieSb.ToString());
                }
            };

            cookieManager.VisitAllCookies(visitor);
        }


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王焜棟琦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值