/// <summary> /// 判断当前已打开的IE中账号 与 当前任务账号 是否一致 /// </summary> /// <param name="info"></param> /// <returns></returns> private bool IsSameAccount(SBillTaskInfo info) { // 未登录,直接登录即可 if (!s_bIsLogining) { return(true); } try { var currUser = getCardInfo(); if (currUser.userName == info.username) { LOGGER.INFO($"当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(info.username)}]和登录用户一致"); return(true); } } catch { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.username)}], 当前在线用户可能不是BCM用户"); return(false); } LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.username)}], 当前在线用户可能不是BCM用户"); return(false); }
/// <summary> /// 判断当前已打开的IE中账号 与 当前任务账号 是否一致 /// </summary> /// <param name="info"></param> /// <returns></returns> private bool IsSameAccount(SBillTaskInfo info) { // 未登录,直接登录即可 if (!s_bIsLogining) { return(true); } // 已登录,从页面获取account try { FKWebDriver.GetInstance.SwitchToFrameByID("contentFrame"); // 这是判断abc,如果不是abc,此项将为0,获取失败 string accountNumber = FKWebDriver.GetInstance.GetAttributeByXPath("//*[@id=\"debit\"]", "data-acctid"); if (String.IsNullOrEmpty(accountNumber)) { LOGGER.INFO($"当前登录用户为空,需要重新登录"); return(false); } if (String.Compare(info.accountNumber, accountNumber, true) != 0) { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.accountNumber)}], 当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(accountNumber)}]"); return(false); } FKWebDriver.GetInstance.SwitchToParentFrame(); } catch { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.accountNumber)}], 当前在线用户可能不是ABC用户"); return(false); } LOGGER.INFO($"当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(info.accountNumber)}]和登录用户一致"); return(true); }
private bool IsSameAccount(SBillTaskInfo info) { // 未登录,直接登录即可 if (!s_bIsLogining) { return(true); } // 已登录,从页面获取account try { // 这是判断ccb,如果不是ccb,此项将为0,获取失败 string userName = FKWebDriver.GetInstance.GetAttributeByXPath("/html/body/div[6]/div[6]/div[1]/div[1]/p/b/span", "title"); if (String.IsNullOrEmpty(userName)) { return(false); } if (String.Compare(info.username, userName, true) != 0) { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.username)}], 当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(userName)}]"); return(false); } } catch { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.username)}], 当前在线用户可能不是CCB用户"); return(false); } LOGGER.INFO($"当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(info.username)}]和登录用户一致"); return(true); }
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> /// 获取查询POST 正文参数 /// </summary> /// <param name="info"></param> /// <returns></returns> private string GetAutoBillPostContent(SBillTaskInfo info, int pageNumber = 1) { // 如下是获取流水必须的参数,对于不懂得参数一律直接传 /* * ACC_NO=6217004220011286774& ->卡号(一个账户下可以挂多个卡号,所以需要提供卡号) * ACC_SIGN =0101010& ->不懂 * TXCODE =310200& ->不懂 * SKEY =lL4XRK& ->这个在登录后首页隐藏的input可以获取到 * USERID =450326199308192729& ->同上 * ACCTYPE2 =12& ->不懂 * PAGE=1& ->页数 * CURRENT_PAGE=1&->页数 * LUGANGTONG =0&->不懂 * START_DATE =20160711&->开始日期 * END_DATE =20170718->结束日期 */ // POST参数表 Dictionary <string, string> postContent = new Dictionary <string, string>(); // 固定参数 postContent.Add("ACC_SIGN", "0101010"); postContent.Add("TXCODE", "310200"); postContent.Add("ACCTYPE2", "12"); postContent.Add("PAGE", $"{pageNumber}"); if (pageNumber == 1) { postContent.Add("flagnext", $"1"); } else { postContent.Add("flagnext", $"4"); } postContent.Add("CURRENT_PAGE", $"1"); postContent.Add("LUGANGTONG", "0"); // 非固定参数 try { postContent.Add("ACC_NO", info.accountNumber); postContent.Add("START_DATE", info.startTime.Substring(0, 8)); postContent.Add("END_DATE", info.endTime.Substring(0, 8)); // 如下路径是通过firebug获取,网页如果有调整此处需要相应调整 // 否则无法获取到对应的element postContent.Add("SKEY", FKWebDriver.GetInstance.GetAttributeByXPath("/html/body/div[6]/div[24]/div[3]/form/input[3]", "value")); postContent.Add("USERID", FKWebDriver.GetInstance.GetAttributeByXPath("/html/body/div[6]/div[24]/div[3]/form/input[4]", "value")); } catch (Exception e) { LOGGER.WARN($"Parser CCB bank post data failed. Error = {e.ToString()}"); return(string.Empty); } // POST参数拼接 return(string.Join("&", postContent.Select(x => x.Key + "=" + x.Value).ToArray())); }
/// <summary> /// 时间过滤器 /// </summary> /// <param name="info"></param> /// <param name="oneBill"></param> /// <returns> false表示被过滤掉 true表示需保留</returns> public static bool TimeFilter(SBillTaskInfo info, string billTime) { string startTime = info.startTime; string endTime = info.endTime; //一天以内数据不做过滤 if (startTime.Substring(0, 8) == endTime.Substring(0, 8)) { return(true); } DateTime dateTimeStart; bool ret = DateTime.TryParseExact(startTime, "yyyyMMdd HH:mm:ss", null, DateTimeStyles.None, out dateTimeStart); if (!ret) { LOGGER.INFO($"过滤开始时间格式错误:{startTime}"); return(true); } DateTime dateTimeEnd; ret = DateTime.TryParseExact(endTime, "yyyyMMdd HH:mm:ss", null, DateTimeStyles.None, out dateTimeEnd); if (!ret) { LOGGER.INFO($"过滤结束时间格式错误:{endTime}"); return(true); } if (dateTimeEnd.CompareTo(dateTimeStart) < 0) { //LOGGER.INFO($"过滤结束时间:{endTime}早于开始时间:{startTime}"); return(true); } DateTime dateTimeSumbmit; ret = DateTime.TryParseExact(billTime, "yyyy-MM-dd HH:mm:ss", null, DateTimeStyles.None, out dateTimeSumbmit); if (!ret) { LOGGER.INFO($"明细时间格式错误:{billTime}"); return(true); } if (dateTimeSumbmit.CompareTo(dateTimeStart) < 0) { //LOGGER.INFO($"删除项时间[{billTime}],过滤开始时间[{startTime}]"); return(false); } else if (dateTimeSumbmit.CompareTo(dateTimeEnd) > 0) { //LOGGER.INFO($"删除项时间[{billTime}],过滤结束时间[{endTime}]"); return(false); } return(true); }
/// <summary> /// 获取 查询POST 内容数据 /// </summary> /// <param name="info"></param> /// <returns></returns> private string GetAutoBillPostContent(SBillTaskInfo info) { // 如下是获取流水必须的参数,对于不懂得参数一律直接传 /* PSessionId=088c8ed8ffff005abb5246f007a67eeb& * x-channel=0& * menuCode=P002000& * step=batchDownLoad& * cardNo=3d6fe2168b70566a7aa44c124f3265cd& * selectCardNo=6222623210002390520& * startDate=20160723& * endDate=20170822& * acoAcRecord=& * queryType=& * serialNo=& * page=1 */ var cardInfo = getCardInfo(); if (string.IsNullOrEmpty(cardInfo.cardNo)) { return(null); } // POST参数表 Dictionary <string, string> postContent = new Dictionary <string, string>(); postContent.Add("x-channel", "0"); postContent.Add("menuCode", "P002000"); postContent.Add("step", "batchDownLoad"); postContent.Add("acoAcRecord", ""); postContent.Add("queryType", ""); postContent.Add("serialNo", ""); postContent.Add("page", "1"); // 非固定参数 try { postContent.Add("PSessionId", cardInfo.PSessionId); postContent.Add("cardNo", cardInfo.uuid); postContent.Add("selectCardNo", cardInfo.cardNo); postContent.Add("startDate", info.startTime.Substring(0, 8)); postContent.Add("endDate", info.endTime.Substring(0, 8)); } catch (Exception e) { LOGGER.WARN($"Parser BCM bank post data failed. Error = {e.ToString()}"); return(string.Empty); } // POST参数拼接 return(string.Join("&", postContent.Select(x => x.Key + "=" + x.Value).ToArray())); }
/// <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 IsSameAccount(SBillTaskInfo info) { // 未登录,直接登录即可 if (!s_bIsLogining) { return(true); } // 已登录,从页面获取account try { // 这是判断abc,如果不是abc,此项将为0,获取失败 string cardCode = FKWebDriver.GetInstance.GetAttributeByXPath("//*[@class=\"each_card\"]", "cardcode"); if (String.IsNullOrEmpty(cardCode)) { LOGGER.INFO($"当前登录用户为空,需要重新登录"); return(false); } string[] cardCodeArr = cardCode.Split('|'); if (cardCodeArr.Length < 2) { LOGGER.INFO($"当前登录用户未找到,需要重新登录"); return(false); } string accountNumber = cardCodeArr[1]; if (String.IsNullOrEmpty(accountNumber)) { LOGGER.INFO($"当前登录用户为空,需要重新登录"); return(false); } if (String.Compare(info.accountNumber, accountNumber, true) != 0) { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.accountNumber)}], 当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(accountNumber)}]"); return(false); } } catch { LOGGER.INFO($"新登录用户[{FKBaseUtils.FKStringHelper.MaskString(info.accountNumber)}], 当前在线用户可能不是CITIC用户"); return(false); } LOGGER.INFO($"当前在线用户[{FKBaseUtils.FKStringHelper.MaskString(info.accountNumber)}]和登录用户一致"); return(true); }
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> /// 获取 查询POST 内容数据 /// </summary> /// <param name="info"></param> /// <returns></returns> private string GetAutoBillPostContent(SBillTaskInfo info) { // 如下是获取流水必须的参数,对于不懂得参数一律直接传 /* acctId=6228482568556511677&acctOpenBankId=34905&acctType=401&provCode=12&acctCurCode=156&oofeFlg=0&trnStartDt=20160804&trnEndDt=20170727' * * acctId 卡号 从传入参数中获取 * acctOpenBankId 开户行 需要从页面提取 * acctType 不懂 但是应该是账户相关 需要从页面提取 * provCode 省份code 页面提取 * acctCurCode 不懂 页面提取 * oofeFlg 不懂 传0 * trnStartDt 开始日期 * trnEndDt 结束日期 */ // POST参数表 Dictionary <string, string> postContent = new Dictionary <string, string>(); // 固定参数,经过实测 只需要acctType 但是这个无法从页面获取 先写死 //postContent.Add("acctOpenBankId", "34905"); postContent.Add("acctType", "401"); //postContent.Add("provCode", "12"); //postContent.Add("acctCurCode", "156"); //postContent.Add("oofeFlg", "0"); // 非固定参数 try { postContent.Add("acctId", info.accountNumber); postContent.Add("trnStartDt", info.startTime.Substring(0, 8)); postContent.Add("trnEndDt", info.endTime.Substring(0, 8)); } catch (Exception e) { LOGGER.WARN($"Parser ABC bank post data failed. Error = {e.ToString()}"); return(string.Empty); } // POST参数拼接 return(string.Join("&", postContent.Select(x => x.Key + "=" + x.Value).ToArray())); }
/// <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> /// 尝试登录 /// </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> /// 解析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); } 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); } }
/// <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); } }
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); }
public void testXls() { SBillTaskResult result = new SBillTaskResult(); SBillTaskInfo info = new SBillTaskInfo(); }
public override bool AutoBill(int nTaskID, SBillTaskInfo info, ref SBillTaskResult result) { throw new NotImplementedException(); }
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="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); }
/// <summary> /// 添加一个新流水查询任务到等待队列 /// </summary> /// <param name="info"></param> internal void AddBillTaskToWaitQueue(SBillTaskInfo info) { LOGGER.INFO($"Add a new bill task to queue. TaskID = {info.taskID}, Time = {info.startTime}-{info.endTime}"); m_BillTasksList.Enqueue(info); }
/// <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);
public S2CMessage_GetBillRequest() { timestamp = 0; signature = ""; info = new SBillTaskInfo(); }
/// <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); }
private static List <SBillTaskInfo> ParseStructFromRequest(string strRequestString, string strCSharpPrivateKey) { JavaScriptSerializer js = new JavaScriptSerializer(); SBillTaskInfo info = new SBillTaskInfo(); List <SBillTaskInfo> result = new List <SBillTaskInfo>(); List <string> beginTimeList = new List <string>(); List <string> endTimeList = new List <string>(); dynamic data; try { data = js.Deserialize <dynamic>(strRequestString); // 反序列化 } catch (Exception e) { LOGGER.WARN($"Server get bill task request is not a invalid JSON format. \n Error = {e.ToString()} \n Request = {strRequestString}"); result.Add(info); return(result); } string strLoginPassword = ""; string strUKeyPassword = ""; try { info.taskID = int.Parse(data["taskID"]); info.bankId = data["bankId"]; info.bankCode = data["bankCode"]; info.bankName = data["bankName"]; info.username = data["username"]; info.accountNumber = data["accountNumber"]; strLoginPassword = data["password"]; strUKeyPassword = data["uKeyPassword"]; { // 时间修正 // 优化时间 2016-09-11 10:59:59 - 2016-09-13 23:59:59 // 原有算法 [2016-09-11 10:59:59 - 2016-09-12 10:59:59] [2016-09-12 10:59:59 - 2016-09-13 23:59:59] // 现有算法 [2016-09-11 10:59:59 - 2016-09-11 23:59:59] [2016-09-12 00:00:00 - 2016-09-12 23:59:59] [2016-09-13 00:00:00 - 2016-09-13 23:59:59] long lStartTime = 0; bool b1 = long.TryParse(data["startTime"], out lStartTime); long lEndTime = 0; bool b2 = long.TryParse(data["endTime"], out lEndTime); if (b1 && b2) { if ((lEndTime - lStartTime) > 86400000) { // 多日要开始分割 // 第一天 DateTime s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); s = s.AddMilliseconds(lStartTime); string strBeginDate = s.ToString("yyyyMMdd HH:mm:ss"); beginTimeList.Add(strBeginDate); endTimeList.Add(strBeginDate.Substring(0, 8) + " 23:59:59"); s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); s = s.AddMilliseconds(lEndTime); string strEndDate = s.ToString("yyyyMMdd HH:mm:ss"); // 中间的天 DateTime middleStart = DateTime.ParseExact( strBeginDate.Substring(0, 8) + " 23:59:59", "yyyyMMdd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture); DateTime middleEnd = DateTime.ParseExact( strEndDate.Substring(0, 8) + " 00:00:00", "yyyyMMdd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture); s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); lStartTime = (long)middleStart.Subtract(s).TotalMilliseconds; lEndTime = (long)middleEnd.Subtract(s).TotalMilliseconds; if (lEndTime > lStartTime) { long lTmpBegin = lStartTime; long lTmpEnd = lTmpBegin + 86400000 - 1000; for (;;) { s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); s = s.AddMilliseconds(lTmpBegin); beginTimeList.Add(s.ToString("yyyyMMdd HH:mm:ss")); s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); s = s.AddMilliseconds(lTmpEnd); endTimeList.Add(s.ToString("yyyyMMdd HH:mm:ss")); lTmpBegin = lTmpEnd + 1; lTmpEnd = lTmpBegin + 86400000 - 1000; if (lTmpBegin >= lEndTime) { break; } if (lTmpEnd >= lEndTime) { lTmpEnd = lEndTime; } } } // 最后一天 beginTimeList.Add(strEndDate.Substring(0, 8) + " 00:00:00"); endTimeList.Add(strEndDate); } else { // 一日之内 DateTime s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); s = s.AddMilliseconds(lStartTime); beginTimeList.Add(s.ToString("yyyyMMdd HH:mm:ss")); s = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); s = s.AddMilliseconds(lEndTime); endTimeList.Add(s.ToString("yyyyMMdd HH:mm:ss")); } } } } catch (Exception e) { LOGGER.WARN($"Parse server get bill task request failed. \n Error = {e.ToString()} \n Request = {strRequestString}"); info.taskID = 0; // 注意清零,外面靠该值判断是否解析成功的 result.Add(info); return(result); } // 解析密码 try { // 根据约定进行RSA解密密码 string xmlKey = FKBaseUtils.FKRSAEncrypt.ConvertRSAPrivateKey_Java2DotNet(strCSharpPrivateKey); info.password = FKBaseUtils.FKRSAEncrypt.RSADecryptByDotNetPrivateKey(strLoginPassword, xmlKey); if (string.IsNullOrEmpty(info.password)) { LOGGER.WARN($"Decrypt password failed. Password = {strLoginPassword}"); info.taskID = 0; result.Add(info); return(result); } info.uKeyPassword = ""; //request.info.uKeyPassword = FKBaseUtils.FKRSAEncrypt.RSADecryptByDotNetPrivateKey(strUKeyPassword, xmlKey); //if (string.IsNullOrEmpty(request.info.uKeyPassword)) //{ // LOGGER.WARN($"Decrypt ukey password failed. Password = {strUKeyPassword}"); // request.info.taskID = 0; // return request.info; //} } catch (Exception e) { LOGGER.WARN($"Decrypt passwords failed. \n Error = {e.ToString()} \n Request = {strRequestString}"); info.taskID = 0; result.Add(info); return(result); } if (beginTimeList.Count != 0 && endTimeList.Count != 0 && beginTimeList.Count == endTimeList.Count) { for (int i = 0; i < beginTimeList.Count; ++i) { SBillTaskInfo tmp = new SBillTaskInfo(); tmp = (SBillTaskInfo)info.Clone(); tmp.startTime = beginTimeList[i]; tmp.endTime = endTimeList[i]; result.Add(tmp); } } return(result); }
/// <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); }
private string GetAutoBillPostContent(SBillTaskInfo info, int pageNumber) { // 如下是获取流水必须的参数,对于不懂得参数一律直接传 /* accountNo=6217680704422380& 卡号 从传入参数中获取 * largeAmount=12& 金额限定 * opFlag=1& 不懂 页面提取 * pageType=1& 页数相关 * payAcctxt=6217680704422380& 卡号 从传入参数中获取 * queryType=spacil& 页数相关 * recordNum=10& 页数相关 * recordSize=10& 页数相关 * recordStart=11& 页数相关 * stdessbgdt=20160804& 开始日期 * stdesseddt=20170727& 结束日期 * stdudfcyno=001& 不懂 * argetPage=11 页数相关 * */ // POST参数表 Dictionary <string, string> postContent = new Dictionary <string, string>(); /*if (File.Exists("data\\citic_auto_bill_content")) * { * var content = File.ReadAllLines("data\\citic_auto_bill_content"); * foreach (var oneLine in content) * { * var keyAndValue = oneLine.Split(' '); * if (keyAndValue.Length >= 2) * { * postContent.Add(keyAndValue[0], keyAndValue[1]); * } * else * { * postContent.Add(keyAndValue[0], ""); * } * } * int onePageNumber = 10; * int recordStart = (onePageNumber * (pageNumber - 1) + 1); * postContent.Add("recordStart", $"{recordStart}"); * postContent.Add("recordNum", $"{onePageNumber}"); * }*/ postContent.Add("currList", ""); postContent.Add("std400pgqf", "N"); postContent.Add("opFlag", "0"); postContent.Add("queryType", "sapcil"); // 非固定参数 try { int onePageNumber = 10; int recordStart = (onePageNumber * (pageNumber - 1) + 1); postContent.Add("recordStart", $"{recordStart}"); postContent.Add("recordNum", $"{onePageNumber}"); postContent.Add("accountNo", info.accountNumber); postContent.Add("payAcctxt", info.accountNumber); postContent.Add("stdessbgdt", info.startTime.Substring(0, 8)); postContent.Add("stdesseddt", info.endTime.Substring(0, 8)); } catch (Exception e) { LOGGER.WARN($"Parser CITIC bank post data failed. Error = {e.ToString()}"); return(string.Empty); } // POST参数拼接 return(string.Join("&", postContent.Select(x => x.Key + "=" + x.Value).ToArray())); }
/// <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); } }