public void testXls() { SBillTaskResult result = new SBillTaskResult(); SBillTaskInfo info = new SBillTaskInfo(); parseXlsContent($"D:\\code\\FKCashier\\FKCashierBank\\bin\\x86\\Debug\\test\\detailabc20170727.xls", ref result, info); }
/// <summary> /// 解析流水页面 /// </summary> /// <param name="html"></param> /// <param name="result"></param> /// <returns></returns> private bool ParseAutoBillHtmlPage(HtmlDocument html, ref SBillTaskResult result, SBillTaskInfo info) { try { var nodes = html.DocumentNode.SelectSingleNode("./table/tbody"); if (nodes == null) { LOGGER.INFO("未找到有效流水数据,可能已经查到最后一页"); return(false); } var items = nodes.SelectNodes("./tr"); if (items == null) { LOGGER.INFO("未找到有效流水数据,可能已经查到最后一页"); return(false); } if (items.Count == 0) { LOGGER.INFO("未找到有效流水数据,可能已经查到最后一页"); return(false); } foreach (var node in nodes.SelectNodes("./tr")) { SBillTaskResult.SBankBillInfo billItem = new SBillTaskResult.SBankBillInfo(); // 解析单一流水对象 if (ParseOneBillHtmlPage(node, ref billItem) == false) { continue; } // citic明细没有时间,一律不过滤 /*if (ResultFilter.TimeFilter(info, billItem.submitTime)) * { * result.billsList.Add(billItem); * }*/ result.billsList.Add(billItem); } result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_Successed; } catch (Exception e) { result.msg = "CITIC解析返回html错误"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; LOGGER.WARN($"CITIC解析返回html错误:{e.Message}"); return(false); } return(true); }
/// <summary> /// 处理流水查询任务 /// </summary> private void HandleBillTask() { try { SBillTaskInfo info = m_BillTasksList.Peek(); // 取出消息,不删除 LOGGER.INFO($"Handle a new bill task:\n {info.ToLogString()} \n, still left {m_BillTasksList.Count - 1} tasks in queue."); SBillTaskResult dealResult = new SBillTaskResult(); dealResult.taskID = info.taskID; dealResult.nodeID = GetCurCashierNodeID(); dealResult.bankId = info.bankId; // 记录当前在处理的任务ID SetCurTaskID(info.taskID); // 开始处理 AutomationBill(info, ref dealResult); LOGGER.WARN($"Auto get bill task is done. Now ready to send msg to server. TaskID = {info.taskID}.", info.taskID); // 发送回馈消息给服务器完毕 HttpSendResult SendResult = RequestSender.SendRequestToServer(dealResult); if (SendResult.IsSendSuccessed()) { SetLastTaskID(info.taskID); SetCurTaskID(INVALID_TASK_ID); LOGGER.INFO($"Send get bill result successed. TaskID = {info.taskID}. \n {SendResult.ToLogString()}"); } else { // result = null; 无论是否发送给服务器成功,只要执行成功,就不允许清除 SetLastTaskID(INVALID_TASK_ID); SetCurTaskID(INVALID_TASK_ID); LOGGER.ERROR($"Send get bill result failed. TaskID = {info.taskID}. \n {SendResult.ToLogString()}", info.taskID); } LOGGER.WARN($"Get bill task deal over. TaskID = {info.taskID}.", info.taskID); } catch (Exception e) { LOGGER.ERROR($"HandleBillTask exception.msg: {e.Message}."); } finally { SetCurTaskID(INVALID_TASK_ID); m_BillTasksList.Dequeue(); // 无论如何,该任务必须删除 } return; }
private bool QueryAutoBill(SBillTaskInfo info, ref SBillTaskResult result) { //return true; if (!s_bIsLogining) { // 未登录 return(false); } result.taskID = info.taskID; try { // 实际测试过程中发现这个链接是随着账号改变,需要在首页中获取 string postUrl = $"https://pbank.95559.com.cn/personbank/account/acTranRecordQuery.stream"; if (string.IsNullOrEmpty(postUrl)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; result.msg = "BCM Post url获取失败"; return(false); } // 构造post content var postContentString = GetAutoBillPostContent(info); if (string.IsNullOrEmpty(postContentString)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; result.msg = "BCM Post content构造失败"; return(false); } // 构造post header var postHeader = GetAutoBillPostHeader(); // POST获取文件 string tmpFile = System.IO.Path.GetTempFileName(); FKHttp.FKHttpClient.POST(postUrl, postContentString, postHeader, 300000, tmpFile); parseXlsContent(tmpFile, ref result, info); } catch (Exception e) { result.msg = $"QueryAutoBill抛出异常[{e.Message}]"; return(false); } return(true); }
/// <summary> /// 解析流水页面 /// </summary> /// <param name="html"></param> /// <param name="result"></param> /// <returns></returns> private bool ParseAutoBillHtmlPage(HtmlDocument html, ref SBillTaskResult result, SBillTaskInfo info) { try { var nodes = html.DocumentNode.SelectSingleNode("//body/form").SelectSingleNode("//table"); var items = nodes.SelectNodes("//tr[@class='td_span']"); // 当获取的数据为空时仍然有一个td_span 但是里面的数据为空 if (items.Count == 1) { if (items[0].GetAttributeValue("zcsr", "") == "|") { return(false); } } foreach (var node in nodes.SelectNodes("//tr[@class='td_span']")) { SBillTaskResult.SBankBillInfo billItem = new SBillTaskResult.SBankBillInfo(); // 解析单一流水对象 if (ParseOneBillHtmlPage(node, ref billItem) == false) { continue; } if (ResultFilter.TimeFilter(info, billItem.submitTime)) { result.billsList.Add(billItem); } } result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_Successed; } catch (Exception e) { result.msg = "CCB解析返回html错误"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; LOGGER.WARN($"CCB解析返回html错误:{e.Message}"); return(false); } return(true); }
/// <summary> /// 自动查询核心函数 /// </summary> /// <param name="nTaskID"></param> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> public override bool AutoBill(int nTaskID, SBillTaskInfo info, ref SBillTaskResult result) { // 判断当前是否是同一个账号 if (!IsSameAccount(info)) { FKWebDriver.GetInstance.Close(); ForceShutdownIE(); s_bIsLogining = false; } // 先尝试进行登录 string logPrefix = $"银行代码[ABC]获取明细,TaskID[{info.taskID}],"; LOGGER.INFO($"{logPrefix}正在尝试登录 ..."); s_bIsLogining = TryLogin(info, ref result); if (!s_bIsLogining) { LOGGER.INFO($"{logPrefix}登录失败,失败原因[{result.msg}]"); FKWebDriver.GetInstance.Close(); ForceShutdownIE(); return(false); } LOGGER.INFO($"{logPrefix}登录成功,开始获取明细"); // 查询 bool ret = QueryAutoBill(info, ref result); if (!ret) { LOGGER.INFO($"{logPrefix}获取明细失败,失败原因[{result.msg}]"); } else { LOGGER.INFO($"{logPrefix}获取明细成功"); } return(ret); }
/// <summary> /// 查询流水 /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool QueryAutoBill(SBillTaskInfo info, ref SBillTaskResult result) { if (!s_bIsLogining) { // 未登录 result.msg = "查流水前未登录"; return(false); } result.taskID = info.taskID; try { // 实际测试过程中发现这个链接是随着账号改变,需要在首页中获取 string postUrl = GetAutoBillPostUrl(); //LOGGER.WARN($"===========================postUrl is {postUrl}"); if (string.IsNullOrEmpty(postUrl)) { result.msg = "获取流水url错误"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; return(false); } for (int i = 1; true; i++) { // 构造post header var postHeader = GetAutoBillPostHeader(); // 构造post content var postContentString = GetAutoBillPostContent(info, i); //LOGGER.WARN($"============================postContentString is {postContentString}"); if (string.IsNullOrEmpty(postContentString)) { result.msg = "构造流水postContent错误"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; return(false); } //string header = string.Join("\r\n", postHeader.Select(x => x.Key + ": " + x.Value).ToArray()); //LOGGER.INFO($"============================postHeader is {header}"); // 使用string的方式获取httpresponse string postResult = FKHttp.FKHttpClient.POST(postUrl, postContentString, postHeader, 300000); //LOGGER.INFO($"response is {postResult}"); // post response是一个Html页面 var doc = new HtmlDocument(); doc.LoadHtml(postResult); /* * string tmpFile = System.IO.Path.GetTempFileName(); * string postResult = FKHttp.FKHttpClient.POST(postUrl, postContentString, postHeader, 300000, tmpFile); * //LOGGER.INFO($"response is {postResult}"); * // post response是一个Html页面 * var doc = new HtmlDocument(); * doc.Load(tmpFile,System.Text.Encoding.UTF8); */ // 解析post response的Html页面 bool bRet = ParseAutoBillHtmlPage(doc, ref result, info); LOGGER.INFO($"第{i}次获取流水之后条数{result.billsList.Count}"); if (bRet == false) { break; } } } catch (Exception e) { result.msg = $"QueryAutoBill抛出异常{e.Message}"; LOGGER.WARN($"Parse CCB bill html page failed. Error = {e.ToString()}"); return(false); } return(true); }
/// <summary> /// 解析XLS文件 /// </summary> /// <param name="filename"></param> /// <param name="result"></param> /// <returns></returns> private bool parseXlsContent(string filename, ref SBillTaskResult result, SBillTaskInfo info) { ExcelReader reader = ExcelReader.CreateReader(filename); try { List <object> recordList = new List <object>(); int i = 0; while (reader.Read(1, ++i, ref recordList)) { // 跳过前三行(标题 本账号信息 列表头) if (i <= 3) { recordList.Clear(); continue; } /* * 交易日期 交易时间 交易金额 本次余额 对方户名 对方账号 交易行 交易渠道 交易类型 交易用途 交易摘要 * 20160828 102524 +270.00 284.91 罗春波 6228270921220010475 江西省分行9999行 网上银行 转账 网银转账 */ SBillTaskResult.SBankBillInfo billItem = new SBillTaskResult.SBankBillInfo(); string date = (string)recordList.ElementAt(0); string time = (string)recordList.ElementAt(1); if (string.IsNullOrEmpty(time)) { time = "000000"; } string dateTime = $"{date}-{time}"; billItem.submitTime = GetTradeTime(dateTime); // 时间不为空的需要过滤 为空总是返回 防止漏掉 if (!string.IsNullOrEmpty((string)recordList.ElementAt(1))) { if (!ResultFilter.TimeFilter(info, billItem.submitTime)) { recordList.Clear(); continue; } } //billItem.amount = Double.Parse($"{(string)recordList.ElementAt(2)}"); //billItem.balance = Double.Parse($"{(string)recordList.ElementAt(3)}"); billItem.amount = ($"{(string)recordList.ElementAt(2)}"); billItem.balance = ($"{(string)recordList.ElementAt(3)}"); billItem.accountName = $"{(string)recordList.ElementAt(4)}"; billItem.accountNumber = $"{(string)recordList.ElementAt(5)}"; billItem.accountBankName = $"{(string)recordList.ElementAt(6)}"; billItem.tradeChannel = $"{(string)recordList.ElementAt(7)}"; billItem.digest = $"{(string)recordList.ElementAt(10)}"; billItem.tradeType = TransformTradeTypeFromSummary($"{(string)recordList.ElementAt(10)}", $"{(string)recordList.ElementAt(2)}"); billItem.tradeUsage = $"{(string)recordList.ElementAt(9)}"; billItem.additionalComment = $"{(string)recordList.ElementAt(10)}"; // 明细未提供 // billItem.currency = ? result.billsList.Add(billItem); recordList.Clear(); } } catch (Exception e) { LOGGER.ERROR($"解析 XLS 文件失败, Error = {e.ToString()}"); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; result.msg = "解析 XLS 文件失败."; return(false); } finally { reader.Close(); } result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_Successed; result.msg = "Successed"; return(true); }
/// <summary> /// 尝试登录 /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool TryLogin(SBillTaskInfo info, ref SBillTaskResult result) { if (s_bIsLogining) { return(true); } bool isOCRPass = false; try { //FKWebDriver webDriver = FKWebDriver.GetInstance; string loginUrl = FKConfig.ABCLoginUrl; // 此部分代码根据现有网银官网的页面设计 // 如果个人银行网页改版,此处可能需要根据新页面做相应调整 FKWebAutomatic.FKWebDriver.GetInstance.OpenUrl(loginUrl); // 等待出现登录界面 var element = FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"username\"]", 30000); if (element == null) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; result.msg = "等待登录账号元素超时,可能页面未正常打开"; return(false); } // 填充登录账号 FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("username", info.username); // 填充密码 LoginPassword(info.password); // 填充验证码,由于验证码可能识别失败,所以需要重试 int retryCount = 20; for (int i = 0; i < retryCount; i++) { string ocr = GetVerificationCodeString(); // 如果识别个数都不对 没必要输入了 重刷验证码再识别 if (ocr.Length == 4) { FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("code", ocr); //移走焦点 FKWebAutomatic.FKWebDriver.GetInstance.ClickByID("username"); // 填充完成后等待识别验证码打钩 Thread.Sleep(5000); // 第一次此元素为隐藏,等待出现 FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"imgError\"]", 10000); // 识别结果获取 string successString = FKWebAutomatic.FKWebDriver.GetInstance.GetAttributeByXPath("//*[@id=\"imgError\"]", "class"); if (successString == "v-code-error right") { // 点击登录 FKWebAutomatic.FKWebDriver.GetInstance.ClickByID("logo"); bool isInput = false; // 用户名提示为空 重新输入 if (FKWebAutomatic.FKWebDriver.GetInstance.IsElementVisiableByXPath("//*[@id=\"username-error\"]")) { LOGGER.INFO("用户名为空,重新输入"); FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("username", info.username); isInput = true; } // 密码提示为空 重新输入 if (FKWebAutomatic.FKWebDriver.GetInstance.IsElementVisiableByXPath("//*[@id=\"powerpass_ie_dyn_Msg\"]")) { LOGGER.INFO("密码为空或者不正确,重新输入"); LoginPassword(info.password, true); isInput = true; } // 多次输入验证码失败后 银行重新清空用户名密码,重填 if (FKWebAutomatic.FKWebDriver.GetInstance.IsElementVisiableByXPath("/html/body/div[2]/div[5]/div/div[1]/div[5]/form/div[5]")) { FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("username", info.username); LoginPassword(info.password, true); isInput = true; } if (isInput) { // 输入后需要重新点击登录 FKWebAutomatic.FKWebDriver.GetInstance.ClickByID("logo"); } isOCRPass = true; break; } Console.WriteLine($"successString = {successString}"); } // 失败 重新刷新验证码 FKWebAutomatic.FKWebDriver.GetInstance.ClickByID("vCode"); Thread.Sleep(1000); } if (!isOCRPass) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; result.msg = "验证码超过重试次数"; return(false); } // 超时等待登陆成功 element = FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"intro4-1\"]", 30000); if (element != null) { LOGGER.INFO("成功获取登录element,登录成功"); return(true); } else { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_LoginFailed; result.msg = $"等待首页超时"; return(false); } } catch (Exception e) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_LoginFailed; result.msg = $"TryLogin抛出异常[[{e.Message}]"; return(false); } }
/// <summary> /// 查询流水(在已登录成功后) /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool QueryAutoBill(SBillTaskInfo info, ref SBillTaskResult result) { /** 完整的获取明细curl命令,此命令最终返回的是一个标准xls的文件,需要进一步解析文件才能提取出明细 * ---------------------------------------------------------------------------------- * curl 'https://perbank.abchina.com/EbankSite/AccountTradeDetailDownloadAct.do' * -H 'Accept: text/html, application/xhtml+xml, *\/*' * - H 'Referer: https://perbank.abchina.com/EbankSite/AccountTradeDetailQueryInitAct.do' * - H 'Accept-Language: zh-CN' * - H 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko' * - H 'Content-Type: application/x-www-form-urlencoded' * - H 'Accept-Encoding: gzip, deflate' * - H 'Host: perbank.abchina.com' * - H 'Content-Length: 136' * - H 'Connection: Keep-Alive' * - H 'Cookie: WT_FPC=id=10.235.177.249-2296909152.30606638:lv=1500978056097:ss=1500977553848; ASP.NET_SessionId=elwlscn2t0puisyczziuwwdt; _ABCPerbankLogonCookie__=; BIGipServerpool_perbank_EbankSite=!Q5CBtVY5fUNWSa38cCqlIAZb8CxfUQboxPynXFLAUdu31cHrqqE7Bl6NuLXg8tH9gLUKWOZc2cVc9J8=' * --data 'acctId=6228482568556511677&acctOpenBankId=34905&acctType=401&provCode=12&acctCurCode=156&oofeFlg=0&trnStartDt=20160804&trnEndDt=20170727' * * ---------------------------------------------------------------------------------- * --data参数解释 * acctId 卡号 从传入参数中获取 * acctOpenBankId 开户行 需要从页面提取 * acctType 不懂 但是应该是账户相关 需要从页面提取 * provCode 省份code 页面提取 * acctCurCode 不懂 页面提取 * oofeFlg 不懂 传0 * trnStartDt 开始日期 * trnEndDt 结束日期 * **/ if (!s_bIsLogining) { // 未登录 return(false); } result.taskID = info.taskID; try { // 实际测试过程中发现这个链接是随着账号改变,需要在首页中获取 string postUrl = FKConfig.ABCBillUrl; if (string.IsNullOrEmpty(postUrl)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; result.msg = "ABC Post url获取失败"; return(false); } // 构造post content var postContentString = GetAutoBillPostContent(info); if (string.IsNullOrEmpty(postContentString)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; result.msg = "ABC Post content构造失败"; return(false); } // 构造post header var postHeader = GetAutoBillPostHeader(); // POST获取文件 string tmpFile = System.IO.Path.GetTempFileName(); string postResult = (string)FKHttp.FKHttpClient.POST(postUrl, postContentString, postHeader, 300000, tmpFile); if (File.Exists(tmpFile)) { bool bRet = parseXlsContent(tmpFile, ref result, info); int nBillCount = 0; if (result.billsList != null) { nBillCount = result.billsList.Count; } LOGGER.INFO($"XLS Tmp file = {tmpFile} InfoLen = {nBillCount}"); //delFile(tmpFile); // TODO: 前期测试不要删除,文件不太大的话,不会引发过多问题,之后版本删除 return(bRet); } else { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; LOGGER.INFO($"Can't find XLS Tmp file = {tmpFile}"); return(false); } } catch (Exception e) { result.msg = $"QueryAutoBill抛出异常[{e.Message}]"; return(false); } }
public void testXls() { SBillTaskResult result = new SBillTaskResult(); SBillTaskInfo info = new SBillTaskInfo(); }
private bool TryLogin(SBillTaskInfo info, ref SBillTaskResult result) { if (s_bIsLogining == false) { try { //FKWebDriver webDriver = FKWebDriver.GetInstance; string loginUrl = FKConfig.BCMLoginUrl; // 此部分代码根据现有交行的页面设计 // 如果交行个人银行网页改版,此处可能需要根据新页面做相应调整 FKWebAutomatic.FKWebDriver.GetInstance.OpenUrl(loginUrl); // 等待出现登录界面 var element = FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("/html/body/div[2]/div/div/div[2]/input", 10000); if (element == null) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; result.msg = $"等待登录页面超时"; return(false); } // 填充登录账号 FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("alias", info.username); // 填充密码 LoginPassword(info.password); // FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("password", info.password); if (FKWebAutomatic.FKWebDriver.GetInstance.IsElementVisiableByID("input_captcha")) { int retryCount = 20; for (int i = 0; i < retryCount; i++) { string ocr = GetVerificationCodeString(); // 如果识别个数都不对 没必要输入了 重刷验证码再识别 if (ocr.Length == 5) { FKWebAutomatic.FKWebDriver.GetInstance.SetTextByID("input_captcha", ocr); //移走焦点 FKWebAutomatic.FKWebDriver.GetInstance.ClickByID("alias"); // 填充完成后等待识别验证码打钩 Thread.Sleep(5000); // 第一次此元素为隐藏,等待出现 FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"captchaFlg\"]", 10000); // 识别结果获取 string successString = FKWebAutomatic.FKWebDriver.GetInstance.GetAttributeByXPath("//*[@id=\"captchaFlg\"]", "class"); if (successString == "right-cpt") { break; } Console.WriteLine($"successString = {successString}"); } // 失败 重新刷新验证码 FKWebAutomatic.FKWebDriver.GetInstance.ClickByXPath("//*[@class=\"captchas-img-bg\"]"); Thread.Sleep(1000); } } // 点击登录 FKWebAutomatic.FKWebDriver.GetInstance.ClickByID("loginBtn"); element = FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"prepareForm\"]", 6000); if (element != null) { var url = FKWebAutomatic.FKWebDriver.GetInstance.GetAttributeByXPath("//*[@id=\"prepareForm\"]", "action"); LOGGER.INFO($"当前url:{url}"); if (url.Contains("syVerifyCustomerNewControl.do") == true) { LOGGER.INFO($"U盾未绑定:{url}"); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; result.msg = $"U盾未绑定"; return(false); } } // 超时 element = FKWebAutomatic.FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"frameMain\"]", 60000); if (element == null) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; result.msg = $"等待主页超时"; return(false); } LOGGER.INFO("登录成功"); Thread.Sleep(1000); if (FKWebAutomatic.FKWebDriver.GetInstance.SwitchToFrameByID("frameMain") == false) { LOGGER.INFO("切换iframe到frameMain失败"); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; result.msg = $"切换iframe失败"; return(false); } string PSessionId = FKWebAutomatic.FKWebDriver.GetInstance.GetAttributeByXPath("//*[@name=\"PSessionId\"]", "value"); LOGGER.INFO($"切换iframe到frameMain成功,PSessionId is {PSessionId}"); //string ReqSafeFields = FKWebAutomatic.FKWebDriver.GetInstance.GetAttributeByXPath("//*[@name=\"ReqSafeFields\"]", "value"); //LOGGER.INFO($"切换iframe到frameMain成功,ReqSafeFields is {ReqSafeFields}"); s_bIsLogining = true; } catch (Exception e) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_LoginFailed; result.msg = $"TryLogin error [{e.Message}]"; return(false); } return(true); } return(s_bIsLogining); }
/// <summary> /// 银行执行自动查流水任务入口函数 /// </summary> /// <param name="nTaskID">任务ID</param> /// <param name="info">信息详细情况:例如登录密码,收款时间限制等</param> /// <param name="result">过程中捕获的详细信息:例如流水情况等</param> /// <returns></returns> public abstract bool AutoBill(int nTaskID, SBillTaskInfo info, ref SBillTaskResult result);
/// <summary> /// 实际自动处理一次流水查询 /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool AutomationBill(SBillTaskInfo info, ref SBillTaskResult result) { // 检查是否支持该银行 int nBankTypeID = GetBillBankTypeIDByName(info.bankCode); if (nBankTypeID <= 0) { LOGGER.ERROR($"Auto bill failed: Unknown bank code - {info.bankCode}"); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_UnsupportBankCode; return(false); } // 检查重要参数是否合法 if (string.IsNullOrEmpty(info.accountNumber) || string.IsNullOrEmpty(info.username) || string.IsNullOrEmpty(info.password)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_ArgumentInvalid; LOGGER.ERROR($"Auto bill failed: account info invalid"); return(false); } // 先进行清理 // 为保持长期登录状态,现不进行清理 - added by Frankie.W 2017-07-19 //{ // FKWebAutomatic.FKWebDriver.GetInstance.FKClose(); // ForceShutdownIE(); // Thread.Sleep(1000); //} DateTime startTime = DateTime.Now; bool bSuccessed = false; BankAutoBillBase imp = null; try { switch (nBankTypeID) { case 1: imp = new CCB_AutoBill(); break; case 2: imp = new BCM_AutoBill(); break; case 3: imp = new CMB_AutoBill(); break; case 4: imp = new ABC_AutoBill(); break; case 5: imp = new CITIC_AutoBill(); break; default: break; } if (imp == null) { LOGGER.ERROR($"Auto bill failed: imp not found"); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_UnknownError; bSuccessed = false; } else { LOGGER.INFO($"Auto bill start: id = {info.taskID}"); imp.Init(); bSuccessed = imp.AutoBill(info.taskID, info, ref result); imp.Clear(); LOGGER.INFO($"Auto bill finish: id = {info.taskID}"); } } catch (Exception e) { LOGGER.ERROR($"Auto bill error occured. Error = {e.ToString()}"); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_UnknownError; bSuccessed = false; } DateTime endTime = DateTime.Now; TimeSpan span = endTime - startTime; if (!bSuccessed) { //LOGGER.ERROR($"Auto bill failed: imp.AutoBill() return false"); // 执行失败 result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; } // 无论成功与否,都要进行清理 // 为保持长期登录状态,现不进行清理 - added by Frankie.W 2017-07-19 //{ // FKWebAutomatic.FKWebDriver.GetInstance.FKClose(); // ForceShutdownIE(); //} // 并记录到日志时间数据库,以便日志查询 FKLog.FKSQLiteLogMgr.GetInstance.AddTaskTimeLog(info.taskID, DateTime.Now); return(bSuccessed); }
private bool ParseAutoBillRegex(string content, ref SBillTaskResult result, SBillTaskInfo info) { Regex reg = new Regex($"\\{{stdessvldt=(?<date>.*?), " + $"stdes2bref=(?<sumary>.*?), " + $"stdes1opna=(?<stdes1opna>.*?), " + $"stdsumtrsq=(?<serialnumber>.*?), " + $"equipmentNO=(?<ignore2>.*?), " + $"stdessrvfg=(?<stdessrvfg>.*?), " + $"std400desc=(?<std400desc>.*?), " + $"stdesstrno=(?<stdesstrno>.*?), " + $"stdes2opid=(?<stdes2opid>.*?), " + $"stdessdcfg=(?<stdessdcfg>.*?), " + $"stdes2bfcd=(?<stdes2bfcd>.*?), " + $"stdessctfg=(?<stdessctfg>.*?), " + $"stdes2opna=(?<stdes2opna>.*?), " + $"stdesstrdt=(?<stdesstrdt>.*?), " + $"stdoppacna=(?<username>.*?), " + $"stdesstram=(?<amount>.*?), " + $"stdessfnfg=(?<stdessfnfg>.*?), " + $"stdes1bfcd=(?<stdes1bfcd>.*?), " + $"stdessacbl=(?<balance>.*?), " + $"stdesstrtm=(?<time>.*?), " + $"stdes1opid=(?<stdes1opid>.*?), " + $"stdesstrcd=(?<stdesstrcd>.*?), " + $"fndoppacno=(?<cardnumber>.*?), " + $"stdoppbrna=(?<bankname>.*?)" + $"\\}}" + $""); var matches = reg.Matches(content); if (matches.Count == 0) { LOGGER.INFO("未找到有效流水数据,可能已经查到最后一页"); return(false); } foreach (Match one in matches) { SBillTaskResult.SBankBillInfo billItem = new SBillTaskResult.SBankBillInfo(); // 解析单一流水对象 billItem.submitTime = GetRegexTradeTime($"{one.Groups["date"].Value}-{one.Groups["time"].Value}"); billItem.serialNo = one.Groups["serialnumber"].Value; if (billItem.serialNo == "null") { billItem.serialNo = ""; } billItem.accountBankName = one.Groups["bankname"].Value; if (billItem.accountBankName == "null") { billItem.accountBankName = ""; } billItem.accountName = one.Groups["username"].Value; if (billItem.accountName == "null") { billItem.accountName = ""; } billItem.additionalComment = one.Groups["sumary"].Value; if (billItem.additionalComment == "null") { billItem.additionalComment = ""; } billItem.balance = one.Groups["balance"].Value; if (billItem.balance == "null") { billItem.balance = ""; } billItem.amount = one.Groups["amount"].Value; if (billItem.amount == "null") { billItem.amount = "0.0"; } billItem.accountNumber = one.Groups["cardnumber"].Value; var inOrOut = one.Groups["stdessdcfg"].Value; if (inOrOut == "C") { billItem.amount = "+" + billItem.amount; } else if (inOrOut == "D") { billItem.amount = "-" + billItem.amount; } else { LOGGER.ERROR($"未知存取类型[{inOrOut}]"); continue; } billItem.tradeType = TransformTradeTypeFromSummary(one.Groups["stdes2bfcd"].Value, inOrOut); if (ResultFilter.TimeFilter(info, billItem.submitTime)) { result.billsList.Add(billItem); } } return(true); }
/// <summary> /// 尝试进行登录 /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool TryLogin(SBillTaskInfo info, ref SBillTaskResult result) { // 已经处於登录状态 if (s_bIsLogining) { return(true); } try { string loginUrl = FKConfig.CITICLoginUrl; // 此部分代码根据现有CITIC的页面设计 // 如果CITIC个人银行网页改版,此处可能需要根据新页面做相应调整 FKWebDriver.GetInstance.OpenUrl(loginUrl); // 等待出现登录界面 var element = FKWebDriver.GetInstance.WaitUntilVisibleByXPath("/html/body/form[1]/div[2]/div[3]/div[1]/ul/li[4]", 20000); if (element == null) { result.msg = "等待登录页超时"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; return(false); } if (FKWebDriver.GetInstance.IsElementVisiableByXPath("//*[@id=\"type2\"]")) { LOGGER.INFO($"检测到U盾,跳过用户名输入"); } else { // 填充登录账号 FKWebDriver.GetInstance.SetTextByName("logonNoCert", info.accountNumber); } // 填充密码 LoginPassword(info.password); var isOcrEnable = FKWebDriver.GetInstance.IsElementVisiableByXPath("//*[@class=\"loginInputVerity\"]"); Console.WriteLine($"isOcrEnable {isOcrEnable}"); var isOcrPass = false; // 处理验证码 if (isOcrEnable) { // 填充验证码 // 由于验证码可能识别失败,所以需要重试 int retryCount = 20; for (int i = 0; i < retryCount; i++) { // 获取ocr string ocr = getOCR(); // 如果识别个数都不对 没必要输入了 重刷验证码再识别 if (ocr.Length == 4) { FKWebAutomatic.FKWebDriver.GetInstance.SetTextByName("verifyCode", ocr.Replace("*", "")); // 填充完成后等待识别验证码打钩 Thread.Sleep(1000); EnterOCRErrorDialog(); // 识别结果获取 string rightSrc = FKWebAutomatic.FKWebDriver.GetInstance.GetAttributeByXPath("//*[@class=\"imgVeritySign\"]", "src"); // 判断验证码是否通过 if (rightSrc.Contains("images/default/start_button.gif")) { isOcrPass = true; break; } Console.WriteLine($"src is [{rightSrc}]"); } // 失败 重新刷新验证码 FKWebDriver.GetInstance.ClickByID("pinImg"); Thread.Sleep(1000); } if (!isOcrPass) { result.msg = "验证码超过重试次数"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; return(false); } } bool logButton = FKWebDriver.GetInstance.DoubleClickByID("logonButton"); // 点击登录 Console.WriteLine($"log button {logButton}"); // 中信银行最近改版,未通过手机绑定的用户会跳转到手机绑定页面 这里处理此页面直接跳过 element = FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@class=\"tradingCon\"]", 30000); if (element == null) { LOGGER.INFO($"未检测出验证页面"); } else { var a = element.FindElement(OpenQA.Selenium.By.TagName("a")); if (a != null && a.Text == "跳过") { LOGGER.INFO($"检测出手机验证页面,点击跳过"); a.Click(); Thread.Sleep(2000); FKWebDriver.GetInstance.ClickByID("jump"); } } // 超时 element = FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@class=\"index_page\"]", 30000); if (element == null) { result.msg = "等待主页超时"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; return(false); } // 到了这里,将认为是成功了 return(true); } catch (Exception e) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_LoginFailed; result.msg = $"TryLogin抛出异常[{e.Message}]"; return(false); } }
/// <summary> /// 查询流水 /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool QueryAutoBill(SBillTaskInfo info, ref SBillTaskResult result) { if (!s_bIsLogining) { // 未登录 return(false); } result.taskID = info.taskID; try { for (int i = 1; true; i++) { string postUrl = $"{FKConfig.CITICBillUrl}?EMP_SID={getEMPSID()}"; if (string.IsNullOrEmpty(postUrl)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; return(false); } // 构造post content var postContentString = GetAutoBillPostContent(info, i); if (string.IsNullOrEmpty(postContentString)) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; return(false); } // 构造post header var postHeader = GetAutoBillPostHeader(); string postHeaderString = string.Join(";", postHeader.Select(x => x.Key + "=" + x.Value).ToArray()); string tmpFile = System.IO.Path.GetTempFileName(); // 获取post response string postResult = (string)FKHttp.FKHttpClient.POST(postUrl, postContentString, postHeader, 300000, tmpFile); Console.WriteLine(postResult); var doc = new HtmlDocument(); doc.Load(tmpFile); var titleNode = doc.DocumentNode.SelectSingleNode("//title"); if (titleNode != null && titleNode.InnerHtml.Trim().Contains($"超时")) { result.msg = "刷新功能正常,获取链接出现主页超时"; LOGGER.WARN(result.msg); s_bIsLogining = false; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; return(false); } //bool bRet = ParseAutoBillHtmlPage(doc, ref result, info); var content = File.ReadAllLines(tmpFile, System.Text.Encoding.GetEncoding("gb2312")); var allContent = String.Join(" ", content); bool bRet = ParseAutoBillRegex(allContent, ref result, info); LOGGER.INFO($"第{i}次获取流水之后条数{result.billsList.Count}"); if (bRet == false) { break; } } } catch (Exception e) { result.msg = $"QueryAutoBill抛出异常{e.Message}"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; LOGGER.WARN($"Parse CCB bill html page failed. Error = {e.ToString()}"); return(false); } if (result.billsList.Count == 0) { result.msg = $"未获取到流水数据"; LOGGER.WARN(result.msg); result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_AutoProcessFailed; return(false); } result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_Successed; return(true); }
public override bool AutoBill(int nTaskID, SBillTaskInfo info, ref SBillTaskResult result) { throw new NotImplementedException(); }
/// <summary> /// 尝试进行登录 /// </summary> /// <param name="info"></param> /// <param name="result"></param> /// <returns></returns> private bool TryLogin(SBillTaskInfo info, ref SBillTaskResult result) { // 已经处於登录状态 if (s_bIsLogining) { return(true); } try { string loginUrl = FKConfig.CCBLoginUrl; // 此部分代码根据现有建行的页面设计 // 如果建行个人银行网页改版,此处可能需要根据新页面做相应调整 FKWebDriver.GetInstance.OpenUrl(loginUrl); // 等待出现登录界面 var element = FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"fclogin\"]", 30000); if (element == null) { result.msg = "等待登录页超时"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; return(false); } // CCB的登录页面是iframe内嵌html,需要首先switch FKWebDriver.GetInstance.SwitchToFrameByID("fclogin"); // 填充登录账号 FKWebDriver.GetInstance.SetTextByID("USERID", info.username); // 填充密码 FKWebDriver.GetInstance.SetTextByID("LOGPASS", info.password); // 点击登录 FKWebDriver.GetInstance.ClickByID("loginButton"); // 超时 element = FKWebDriver.GetInstance.WaitUntilVisibleByXPath("//*[@id=\"pnav_V6010000\"]", 30000); if (element == null) { result.msg = "等待主页超时"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_WaitElementTimeout; return(false); } if (!FKWebDriver.GetInstance.ClickByID("pnav_V6020000")) { result.msg = "点击首页出错"; result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_LoginFailed; return(false); } // 到了这里,将认为是成功了 return(true); } catch (Exception e) { result.status = (int)SBillTaskResult.ENUM_BillActionStatus.eBillActionStatus_LoginFailed; result.msg = $"TryLogin抛出异常[{e.Message}]"; return(false); } }