573 lines
23 KiB
C#
573 lines
23 KiB
C#
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 关闭所有Cef进程
|
|
/// </summary>
|
|
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<bool> SetProxyAsync(ChromiumWebBrowser cefWebBrowser, string proxyUrl)
|
|
{
|
|
bool isUseProxy = false;
|
|
await Cef.UIThreadTaskFactory.StartNew(() =>
|
|
{
|
|
try
|
|
{
|
|
var rc = cefWebBrowser.GetBrowser().GetHost().RequestContext;
|
|
var dict = new Dictionary<string, object>();
|
|
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<Cookie> cookieList)
|
|
{
|
|
string cookies = string.Empty;
|
|
foreach (Cookie cookie in cookieList)
|
|
{
|
|
cookies += string.Format("{0}={1};", cookie.Name, cookie.Value);
|
|
}
|
|
return cookies;
|
|
}
|
|
|
|
public static List<Cookie> 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<Cookie> list = new List<Cookie>();
|
|
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<Cookie> 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<Cookie> list = JsonConvert.DeserializeObject<List<Cookie>>(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<long> frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers();
|
|
//foreach (long identifier in frameIdentifierList)
|
|
List<string> 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<string, string, bool> checkUrl)
|
|
{
|
|
// cef138
|
|
//List<long> frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers();
|
|
//foreach (long identifier in frameIdentifierList)
|
|
List<string> 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<JavascriptResponse> EvaluateScriptAsync(ChromiumWebBrowser cefWebBrowser, string js)
|
|
{
|
|
JavascriptResponse javascriptResponse = await cefWebBrowser.GetBrowser().MainFrame.EvaluateScriptAsync(js);
|
|
return javascriptResponse;
|
|
}
|
|
|
|
public static async Task<JavascriptResponse> EvaluateScriptAsync(ChromiumWebBrowser cefWebBrowser, string url, string js, Func<string, string, bool> checkUrl)
|
|
{
|
|
// cef138
|
|
JavascriptResponse javascriptResponse = new JavascriptResponse();
|
|
//List<long> frameIdentifierList = cefWebBrowser.GetBrowser().GetFrameIdentifiers();
|
|
//foreach (long identifier in frameIdentifierList)
|
|
List<string> 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<JavascriptResponse> 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 模拟鼠标滑动
|
|
/// </summary>
|
|
/// <param name="host"></param>
|
|
/// <param name="fromX">左边缘Left</param>
|
|
/// <param name="fromY">左边缘Top</param>
|
|
/// <param name="toX">右边缘Left</param>
|
|
/// <param name="toY">右边缘Top</param>
|
|
/// <param name="slideWidth">滑块的宽度</param>
|
|
/// <param name="slideHeight">滑块的高度</param>
|
|
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));
|
|
}
|
|
}
|
|
}
|