using CefSharp; using CefSharp.WinForms; using NaiBa.CefHelper; using NaiBa.CefHelper.Handler; using NaiBa.Util; using NaiBa.Util.Extension; using NaiBa.Util.Helper; using NaiBa.Util.Model; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Work._29Tools.CefTools { public class LocalCEFBrowser { public static bool IsKeepGlobalCookie = true; // true 的时候,cookie 会保存在硬盘上,cookie 是持久化的 public static string CefGlobalCachePath = Path.Combine(FileHelper.GetApplicationDir(), "cef_temp"); public static string CefMemoryCachePath = Path.Combine(CefGlobalCachePath, "memory"); public static void Init(string userAgent = "") { // 必须在主线程进行初始化 if (NaiBaGlobalConfig.IsDevelopment) { FileHelper.DeleteFolder(CefGlobalCachePath); } FileHelper.CreateDirectory(CefGlobalCachePath); CefSharpSettings.WcfEnabled = false; CefSettings settings = new CefSettings { IgnoreCertificateErrors = false, Locale = "zh-CN", PersistSessionCookies = true, //PersistUserPreferences = true, //cef138 LogFile = Path.Combine(CefGlobalCachePath, "debug.log"), LogSeverity = NaiBaGlobalConfig.IsDevelopment ? LogSeverity.Verbose : LogSeverity.Error, CachePath = IsKeepGlobalCookie ? CefGlobalCachePath : string.Empty, RootCachePath = IsKeepGlobalCookie ? CefGlobalCachePath : string.Empty }; settings.UserAgent = string.IsNullOrEmpty(userAgent) ? NaiBaGlobalConfig.UserAgent : userAgent; settings.CefCommandLineArgs.Add("disable-gpu", "1"); settings.CefCommandLineArgs.Add("--ignore-ssl-errors"); settings.CefCommandLineArgs.Add("--disable-web-security"); settings.CefCommandLineArgs.Add("--allow-file-access-from-files"); // 允许通过 file:/// 协议访问 Worker System.Net.IWebProxy webProxy = NaiBaGlobalConfig.GetDevelopProxy(); if (webProxy != null) { if (NaiBaGlobalConfig.IsDevelopment) { bool isSetFiddlerProxy = false; // 由于店铺可能绑定了代理,浏览器不设置 Fiddler 代理 if (isSetFiddlerProxy) { string address = ReflectionHelper.GetObjectPropertyValue(webProxy, "Address").ParseToString(); if (!address.IsNullOrEmpty()) { address = address.Trim('/'); // Don't set any proxy during initialize,becuase once setting,it couldn't be changed at runtime settings.CefCommandLineArgs.Add("--proxy-server", address); } } } } var rst = Cef.Initialize(settings); } /// /// 关闭所有Cef进程 /// public static void ShutDown() { Cef.Shutdown(); } public static ChromiumWebBrowser CreateChromiumWebBrowser(string url, bool isGlobal = true, bool isPopupNewWindow = true) { ChromiumWebBrowser cefBrowser = new ChromiumWebBrowser(url); if (!isGlobal) { cefBrowser.RequestContext = new RequestContext(GetRequestContextIsolateSettings()); } cefBrowser.BrowserSettings = new BrowserSettings { Javascript = CefState.Enabled, JavascriptAccessClipboard = CefState.Enabled, JavascriptCloseWindows = CefState.Enabled, JavascriptDomPaste = CefState.Enabled, LocalStorage = CefState.Enabled, //Plugins = CefState.Disabled, //cef138 //FileAccessFromFileUrls = CefState.Enabled, //cef138 //UniversalAccessFromFileUrls = CefState.Enabled //cef138 }; cefBrowser.KeyboardHandler = new KeyboardHandler(); cefBrowser.MenuHandler = new MenuHandler(); cefBrowser.LifeSpanHandler = new LifeSpanHandler(isPopupNewWindow); return cefBrowser; } public static RequestContextSettings GetRequestContextIsolateSettings() { RequestContextSettings requestContextSettings = new RequestContextSettings() { PersistSessionCookies = true, CookieableSchemesExcludeDefaults = false, }; //requestContextSettings.PersistSessionCookies = false; //requestContextSettings.PersistUserPreferences = false; // cef138 return requestContextSettings; } public static void CheckCefPlatform() { string executingFolder = FileHelper.GetApplicationDir(); //If libcef.dll doesn't exist in our executing folder then we'll copy the files //For this method the user must have write permissions to the executing folder. if (!File.Exists(Path.Combine(executingFolder, "libcef.dll"))) { var libPath = Path.Combine(executingFolder, Environment.Is64BitProcess ? "x64" : "x86"); if (Directory.Exists(libPath)) { FileHelper.MoveFolder(libPath, executingFolder); } string dir = executingFolder + "x86"; if (Directory.Exists(dir)) { Directory.Delete(dir, recursive: true); } dir = executingFolder + "x64"; if (Directory.Exists(dir)) { Directory.Delete(dir, recursive: true); } } } public static async Task SetProxyAsync(ChromiumWebBrowser cefWebBrowser, string proxyUrl) { bool isUseProxy = false; await Cef.UIThreadTaskFactory.StartNew(() => { try { var rc = cefWebBrowser.GetBrowser().GetHost().RequestContext; var dict = new Dictionary(); if (string.IsNullOrEmpty(proxyUrl)) { dict.Add("mode", "system"); } else { var objProxy = HttpHelper.ResoveProxyServer(proxyUrl); if (objProxy.Tag == 1) { BaseProxyServer baseProxyServer = objProxy.Data; if (!baseProxyServer.Username.IsNullOrEmpty() && !baseProxyServer.Password.IsNullOrEmpty()) { CustomRequestHandler customRequestHandler = cefWebBrowser.RequestHandler as CustomRequestHandler; if (customRequestHandler != null) { customRequestHandler.UserName = baseProxyServer.Username; customRequestHandler.Password = baseProxyServer.Password; } } proxyUrl = string.Format("http://{0}:{1}", baseProxyServer.ServerIP, baseProxyServer.ServerPort); } dict.Add("mode", "fixed_servers"); // fixed_servers,pac_script,auto_detect,system,direct dict.Add("server", proxyUrl); } string error; bool success = rc.SetPreference("proxy", dict, out error); if (success) { isUseProxy = true; } } catch (Exception ex) { LogHelper.WriteWithTime(ex); } }); return isUseProxy; } public static string ParseCookieListToString(List cookieList) { string cookies = string.Empty; foreach (Cookie cookie in cookieList) { cookies += string.Format("{0}={1};", cookie.Name, cookie.Value); } return cookies; } public static List GetCookieList(string domains = "", ICookieManager cookieManager = null) { if (cookieManager == null) { cookieManager = Cef.GetGlobalCookieManager(); } CookieVisitor visitor = new CookieVisitor(); if (cookieManager.VisitAllCookies(visitor)) { visitor.WaitForAllCookie(); } if (string.IsNullOrEmpty(domains)) { return visitor.CookieList; } else { List list = new List(); foreach (string domain in domains.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)) { list.AddRange(visitor.CookieList.Where(p => p.Domain != null && p.Domain.Contains(domain.Trim())).ToList()); } return list; } } public static string GetCookie(string domains = "", ICookieManager cookieManager = null) { List cookieList = GetCookieList(domains, cookieManager); string cookies = ParseCookieListToString(cookieList); return cookies; } public static async Task SetCookieAsync(string domain, string cookies, ICookieManager cookieManager = null) { try { foreach (string cookie in cookies.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)) { int i = cookie.IndexOf('='); if (i > 0) { string name = cookie.Substring(0, i).ToString().Trim(); string value = cookie.Substring(i + 1).ToString().Trim(); if (name.ToLower() == "expires" || name.ToLower() == "path" || name.ToLower() == "domain") { continue; } Cookie newCookie = new Cookie { Domain = domain, Name = name, Value = value, Path = "/" }; if (cookieManager == null) { bool result = await Cef.GetGlobalCookieManager().SetCookieAsync("http://" + domain, newCookie); } else { bool result = await cookieManager.SetCookieAsync("http://" + domain, newCookie); } } } } catch { } } public static async Task SetCookieAsync(string cookieList, ICookieManager cookieManager = null) { try { if (!string.IsNullOrEmpty(cookieList)) { List list = JsonConvert.DeserializeObject>(cookieList); foreach (Cookie cookie in list) { cookie.Secure = false; if (cookieManager == null) { bool result = await Cef.GetGlobalCookieManager().SetCookieAsync("http://" + cookie.Domain.Trim('.'), cookie); } else { bool result = await cookieManager.SetCookieAsync("http://" + cookie.Domain.Trim('.'), cookie); } } } } catch (Exception ex) { LogHelper.WriteWithTime(ex); } } public static async Task DeleteCookieAsync(ICookieManager cookieManager, string domain = "", string name = "") { string url = string.Empty; if (!string.IsNullOrEmpty(domain)) { url = "http://" + domain; } if (cookieManager == null) { int result = await Cef.GetGlobalCookieManager().DeleteCookiesAsync(url, name); } else { int result = await cookieManager.DeleteCookiesAsync(url, name); } } public static void DeleteCookie(ICookieManager cookieManager, string domain = "", string name = "") { string url = string.Empty; if (!string.IsNullOrEmpty(domain)) { url = "http://" + domain; } if (cookieManager == null) { bool result = Cef.GetGlobalCookieManager().DeleteCookies(url, name); } else { bool result = cookieManager.DeleteCookies(url, name); } } public static void ExecJavascript(ChromiumWebBrowser cefWebBrowser, string js) { // cef138 //List frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers(); //foreach (long identifier in frameIdentifierList) List frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers(); foreach (string identifier in frameIdentifierList) { //IFrame frame = cefWebBrowser.GetBrowser().GetFrame(identifier); IFrame frame = cefWebBrowser.GetBrowser().GetFrameByIdentifier(identifier); if (frame.IsMain) { frame.ExecuteJavaScriptAsync(js); break; } } } public static void ExecJavascript(ChromiumWebBrowser cefWebBrowser, string expectUrl, string js, Func checkUrl) { // cef138 //List frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers(); //foreach (long identifier in frameIdentifierList) List frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers(); foreach (string identifier in frameIdentifierList) { //IFrame frame = cefWebBrowser.GetBrowser().GetFrame(identifier); IFrame frame = cefWebBrowser.GetBrowser().GetFrameByIdentifier(identifier); if (checkUrl(frame.Url, expectUrl)) { frame.ExecuteJavaScriptAsync(js); break; } } } public static void ExecJavascriptEqualsUrl(ChromiumWebBrowser cefWebBrowser, string url, string js) { ExecJavascript(cefWebBrowser, url, js, (frameUrl, expectUrl) => { if (frameUrl.Equals(expectUrl)) { return true; } else { return true; } }); } public static void ExecJavascriptStartsWithUrl(ChromiumWebBrowser cefWebBrowser, string url, string js) { ExecJavascript(cefWebBrowser, url, js, (frameUrl, expectUrl) => { if (frameUrl.StartsWith(expectUrl)) { return true; } else { return true; } }); } public static void ExecJavascriptContainsUrl(ChromiumWebBrowser cefWebBrowser, string url, string js) { ExecJavascript(cefWebBrowser, url, js, (frameUrl, expectUrl) => { if (frameUrl.Contains(expectUrl)) { return true; } else { return false; } }); } public static JavascriptResponse EvaluateScript(ChromiumWebBrowser cefWebBrowser, string js) { JavascriptResponse javascriptResponse = null; Task task = Task.Run(async () => { javascriptResponse = await cefWebBrowser.GetBrowser().MainFrame.EvaluateScriptAsync(js); return javascriptResponse; }); task.Wait(); return javascriptResponse; } public static async Task EvaluateScriptAsync(ChromiumWebBrowser cefWebBrowser, string js) { JavascriptResponse javascriptResponse = await cefWebBrowser.GetBrowser().MainFrame.EvaluateScriptAsync(js); return javascriptResponse; } public static async Task EvaluateScriptAsync(ChromiumWebBrowser cefWebBrowser, string url, string js, Func checkUrl) { // cef138 JavascriptResponse javascriptResponse = new JavascriptResponse(); //List frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers(); //foreach (long identifier in frameIdentifierList) List frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers(); foreach (string identifier in frameIdentifierList) { //IFrame frame = cefWebBrowser.GetBrowser().GetFrame(identifier); IFrame frame = cefWebBrowser.GetBrowser().GetFrameByIdentifier(identifier); if (checkUrl(frame.Url, url)) { javascriptResponse = await frame.EvaluateScriptAsync(js); } } return javascriptResponse; } public static string GetElementLocation(ChromiumWebBrowser cefWebBrowser, string elementIdOrClass) { string js = @"function getElementLocation() { var element = document.getElementById('{0}'); if (element == null || element == undefined) { var elements = document.getElementsByClassName('{0}'); if(elements){ element = elements[0]; } } if (element == null || element == undefined) { return '0,0,0,0'; } return element.getBoundingClientRect().left.toString() + ',' + element.getBoundingClientRect().top.toString() + ',' + (element.width?element.width.toString():element.getBoundingClientRect().width) + ',' + (element.height?element.height.toString():element.getBoundingClientRect().height); } getElementLocation(); "; string formatJs = js.Replace("{0}", elementIdOrClass); Task task = cefWebBrowser.EvaluateScriptAsync(formatJs); task.Wait(2000); string location = task.Result.Result.ParseToString(); return location; } public static LocationPoint GetElementLocationPoint(ChromiumWebBrowser cefWebBrowser, string elementIdOrClass) { LocationPoint locationPoint = new LocationPoint(); string location = GetElementLocation(cefWebBrowser, elementIdOrClass); if (location.Contains(",")) { string[] xy = location.Split(','); locationPoint.Left = xy[0].DecimalPointParseToInt(); locationPoint.Top = xy[1].DecimalPointParseToInt(); locationPoint.Width = xy[2].DecimalPointParseToInt(); locationPoint.Height = xy[3].DecimalPointParseToInt(); } return locationPoint; } public static void SimulateMouseLeftClick(IBrowserHost host, int x, int y) { Random random = new Random(Guid.NewGuid().GetHashCode()); host.SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.None); // 按下鼠标左键 Thread.Sleep(75 + random.Next(50)); host.SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None); // 松开鼠标左键 Thread.Sleep(300); } /// /// 模拟鼠标滑动 /// /// /// 左边缘Left /// 左边缘Top /// 右边缘Left /// 右边缘Top /// 滑块的宽度 /// 滑块的高度 public static void SimulateMouseMove(IBrowserHost host, int fromX, int fromY, int toX, int toY, int slideWidth = 0, int slideHeight = 0) { Thread.Sleep(RandomHelper.GetRandom(0, 50)); int randomX = 0; int randomY = 0; if (slideWidth == 0) { randomX = -2 + RandomHelper.GetRandom(0, 5); } else { randomX = RandomHelper.GetRandom(0, slideWidth); } if (slideHeight == 0) { randomY = -2 + RandomHelper.GetRandom(0, 5); } else { randomY = RandomHelper.GetRandom(0, slideHeight); } int x = fromX + randomX; int y = fromY + randomY; host.SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.None); // 按下鼠标左键 Thread.Sleep(200 + RandomHelper.GetRandom(0, 200)); int times = 0; while (x < toX - 4) // 后半部分 { times++; x += 4 + RandomHelper.GetRandom(0, 4); y = y - 1 + RandomHelper.GetRandom(0, 3); Thread.Sleep(6 + times / 6 + RandomHelper.GetRandom(0, 4)); host.SendMouseMoveEvent(x, y, false, CefEventFlags.LeftMouseButton); // 移动鼠标 } x = toX - 1 + RandomHelper.GetRandom(0, 3); Thread.Sleep(100 + RandomHelper.GetRandom(0, 100)); host.SendMouseMoveEvent(x, y, false, CefEventFlags.LeftMouseButton); // 移动鼠标 Thread.Sleep(400 + RandomHelper.GetRandom(0, 600)); host.SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None); // 抬起鼠标左键 } public static void SimulateInputChar(IBrowserHost host, int key) { Random random = new Random(); host.SendKeyEvent(new KeyEvent() { WindowsKeyCode = key, Type = KeyEventType.KeyDown }); Thread.Sleep(10 + random.Next(10)); host.SendKeyEvent(new KeyEvent() { WindowsKeyCode = key, Type = KeyEventType.Char }); Thread.Sleep(50 + random.Next(40)); host.SendKeyEvent(new KeyEvent() { WindowsKeyCode = key, Type = KeyEventType.KeyUp }); Thread.Sleep(50 + random.Next(40)); } } }