使用webkit内核实现从票根网自动选取并开立发票,自动下载发票(好吧,其实是半自动)。本来已经用webBrowser实现了一个,但是测试的时候出现各种UI不兼容的情况,于是使用webkit内核进行替换。
主要包含以下几个技术点(其实也就是cefsharp常用的几个点)
1.引进Nuget包(不废话)
2.新建控件
不能直接拖拽布局,只能用代码向容器内布置控件
public ChromiumWebBrowser ThisWeb;//新建对象
在Init方法后添加初始化和布局函数
public void InitializeChromium()
{
CefSettings settings = new CefSettings();//新建设置对象
Cef.Initialize(settings);//加载设置
ThisWeb = new ChromiumWebBrowser("https://sso.txffp.com/sso/app/oauth/login?client_id=000031&response_type=code&redirect_uri=https://pss.txffp.com/pss/app/oauth/login&scope=USERINFO&state=state");//初始化访问
ThisWeb.LifeSpanHandler = new OpenPageSelf();//禁止外部打开
ThisWeb.IsBrowserInitializedChanged += ThisWeb_IsBrowserInitializedChanged;
ThisWeb.DownloadHandler = new MyDownLoadFile();
this.splitContainer1.Panel1.Controls.Add(ThisWeb);
TextBox txt = new TextBox();
ThisWeb.Dock = DockStyle.Fill;
}
其中有两段代码是为了满足后续需求添加的,分别是禁止开启新浏览器窗口(强制本地打开)和对下载事件的响应。
禁止外部打开及其实现
ThisWeb.LifeSpanHandler = new OpenPageSelf();//禁止外部打开
#region 禁止外部新建
internal class OpenPageSelf : ILifeSpanHandler
{
public bool DoClose(IWebBrowser browserControl, IBrowser browser)
{
return false;
}
public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser)
{
}
public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser)
{
}
public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl,
string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures,
IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
newBrowser = null;
var chromiumWebBrowser = (ChromiumWebBrowser)browserControl;
chromiumWebBrowser.Load(targetUrl);
return true; //Return true to cancel the popup creation copyright by codebye.com.
}
}
#endregion
下载事件的响应接口如下(继承自IDownloadHandler类)
public class MyDownLoadFile : IDownloadHandler
{
public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
if (!callback.IsDisposed)
{
using (callback)
{
callback.Continue(@"\" +FrmMain.DownloadFilePath,showDialog: true);
}
}
}
public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
return;
}
}
其中callback.continue函数比较重要,其会直接影响下载事件的执行
callback.Continue(@"\" +FrmMain.DownloadFilePath,showDialog: true);
//第一个参数是下载路径,第二个参数为是否显示对话框
在对象初始化的时候对重载的类进行托管
ThisWeb.IsBrowserInitializedChanged += ThisWeb_IsBrowserInitializedChanged;
ThisWeb.DownloadHandler = new MyDownLoadFile();
2.表单的自动填充
当准备好对象后为了实现表单自动填充和自动登录,我们需要两个方法:向输入框中填充帐号密码、自动点击登录按键
private void Login()
{
ThisWeb.EvaluateScriptAsync("document.querySelector('input[name=loginName]').value='帐号';");
ThisWeb.EvaluateScriptAsync("document.querySelector('input[name=passwd]').value='密码';");
ThisWeb.EvaluateScriptAsync("document.querySelector('a[id=submitButton]').click();");
}
CefSharp采用js脚本进行执行,主要依靠修改括号中的语句实现功能。例如
document.querySelector('控件类型[查询条件=查询目标]').需要触发的事件();
3.获取HTML文本
基本有这几个方法即可构成整个系统,但是还有一个问题,就是如何抓取车牌号,很不幸的是票根网的车牌号没有有效的查询条件,这里直接采用“土办法”,用符号">"切割整个html文档然后找到关键字“湘”(经过验证包含湘的必定为车牌号),然后再摘掉多余的部分即可得到车牌号。
public string[] GetElems(string htmlCode)//拆解HTML文本
{
List<string> ElemList = new List<string>();
string[] sArray = htmlCode.Split('>');//按>切割文本
return sArray;
}
public string GetCarId(string[] ElemList)//获取车牌元素
{
string Temp = ElemList.First(x => x.Contains("湘"));//找到第一个包含条件的元素
string[] sArray = Temp.Split('<');//摘除多余部分
return sArray[0];
}
抓取控件中的HTML文本
var task1 = await ThisWeb.GetSourceAsync();//获取全部html文本
string carid = GetCarId(GetElems(task1.ToString()));//转换
4.最后就是一个跳转事件,用于一键回到对应的页面
ThisWeb.Load("https://pss.txffp.com/pss/app/login/invoice/query/card/COMPANY");
上一点展示图