JSTC7WSJob.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using HtmlAgilityPack;
  7. using Quartz;
  8. using SCC.Common;
  9. using SCC.Crawler.Tools;
  10. using SCC.Interface;
  11. using SCC.Models;
  12. namespace SCC.Crawler.DT
  13. {
  14. /// <summary>
  15. /// 江苏体彩7位数
  16. /// </summary>
  17. [DisallowConcurrentExecution]
  18. [PersistJobDataAfterExecution]
  19. public class JSTC7WSJob : IJob
  20. {
  21. /// <summary>
  22. /// 初始化函数
  23. /// </summary>
  24. public JSTC7WSJob()
  25. {
  26. log = new LogHelper();
  27. services = IOC.Resolve<IDTOpenCode>();
  28. email = IOC.Resolve<IEmail>();
  29. }
  30. /// <summary>
  31. /// 作业执行入口
  32. /// </summary>
  33. /// <param name="context">作业执行上下文</param>
  34. public void Execute(IJobExecutionContext context)
  35. {
  36. Config = CommonHelper.GetConfigFromDataMap(context.JobDetail.JobDataMap);
  37. //预设节假日不开奖
  38. if (Config.SkipDate.Contains(CommonHelper.SCCSysDateTime.ToString("yyyyMMdd"))) return;
  39. LatestItem = context.JobDetail.JobDataMap["LatestItem"] as OpenCode7DTModel;
  40. try
  41. {
  42. //服务启动时配置初始数据
  43. if (LatestItem == null)
  44. {
  45. LatestItem = services.GetOpenCode7DTLastItem(currentLottery);
  46. if (LatestItem == null)
  47. LatestItem = new OpenCode7DTModel
  48. {
  49. Term = CommonHelper.GenerateQiHaoYYQQQ(0),
  50. OpenTime = new DateTime(CommonHelper.SCCSysDateTime.Year, 1, 1)
  51. };
  52. }
  53. //程序时间第二天,程序根据配置检查是否昨天有开奖
  54. isGetData = false;
  55. if (CommonHelper.CheckDTIsNeedGetData(Config))
  56. {
  57. DoMainUrl();
  58. DoBackUrl();
  59. }
  60. if (!LatestItem.Term.ToString().StartsWith(CommonHelper.SCCSysDateTime.ToString("yy")))
  61. LatestItem = new OpenCode7DTModel
  62. {
  63. Term = CommonHelper.GenerateQiHaoYYQQQ(0),
  64. OpenTime = new DateTime(CommonHelper.SCCSysDateTime.Year, 1, 1)
  65. };
  66. //当今日开奖并且当前时间是晚上8点过后开始抓取
  67. if (CommonHelper.CheckTodayIsOpenDay(Config) && CommonHelper.SCCSysDateTime.Hour > 12)
  68. {
  69. DoMainUrl();
  70. DoBackUrl();
  71. }
  72. //
  73. // TrendChartHelper.GenerateJSTC7WSTrendChart(log);
  74. }
  75. catch (Exception ex)
  76. {
  77. log.Error(typeof(JSTC7WSJob),
  78. string.Format("【{0}】抓取时发生错误,错误信息【{1}】", Config.Area + currentLottery, ex.Message));
  79. }
  80. //保存最新期号
  81. context.JobDetail.JobDataMap["LatestItem"] = LatestItem;
  82. }
  83. /// <summary>
  84. /// 通过主站点爬取开奖数据
  85. /// (江苏体彩网)
  86. /// </summary>
  87. private void DoMainUrl()
  88. {
  89. if (!string.IsNullOrEmpty(Config.MainUrl))
  90. {
  91. var OpenList = GetOpenListFromMainUrl(Config.MainUrl);
  92. if (OpenList.Count == 0) return; //无抓取数据
  93. var newestQiHao = OpenList.First().Term.ToString();
  94. var startQiNum = Convert.ToInt32(LatestItem.Term.ToString().Substring(2)) + 1;
  95. var newestQiNum = Convert.ToInt32(newestQiHao.Substring(2));
  96. if (startQiNum > newestQiNum) return; //无最新数据
  97. //处理最新开奖数据
  98. var getQiHao = string.Empty;
  99. OpenCode7DTModel matchItem = null;
  100. for (var i = startQiNum; i <= newestQiNum; i++)
  101. {
  102. getQiHao = LatestItem.Term.ToString().Substring(0, 2) + i.ToString().PadLeft(3, '0');
  103. matchItem = OpenList.Where(R => R.Term.ToString() == getQiHao).FirstOrDefault();
  104. if (matchItem != null && OptimizeMainModel(ref matchItem) &&
  105. services.AddDTOpen7Code(currentLottery, matchItem))
  106. {
  107. //Do Success Log
  108. log.Info(typeof(JSTC7WSJob), CommonHelper.GetJobMainLogInfo(Config, getQiHao));
  109. LatestItem = matchItem;
  110. isGetData = true;
  111. }
  112. }
  113. }
  114. }
  115. /// <summary>
  116. /// 获取主站开奖列表数据
  117. /// </summary>
  118. /// <param name="mainUrl">主站地址</param>
  119. /// <returns></returns>
  120. private List<OpenCode7DTModel> GetOpenListFromMainUrl(string mainUrl)
  121. {
  122. var result = new List<OpenCode7DTModel>();
  123. try
  124. {
  125. var pageIndex = 1;
  126. var htmlResource = string.Empty;
  127. var resourceUrl = new Uri(mainUrl);
  128. var isLoop = true;
  129. var lastYear = (DateTime.Now.Year - 1).ToString().Substring(2);
  130. var postData = "current_page={0}&all_count=0&num=";
  131. var OpenTime = string.Empty;
  132. while (isLoop)
  133. {
  134. htmlResource = NetHelper.GetUrlResponse(resourceUrl.AbsoluteUri, "POST",
  135. string.Format(postData, pageIndex), Encoding.UTF8);
  136. var jsonData = htmlResource.JsonToEntity<dynamic>();
  137. var dataList = jsonData["items"];
  138. foreach (var data in dataList)
  139. {
  140. if (data["num"].Value.StartsWith(lastYear))
  141. {
  142. isLoop = false;
  143. break;
  144. }
  145. OpenTime = data["date_publish"].Value.Insert(6, "-").Insert(4, "-");
  146. result.Add(new OpenCode7DTModel
  147. {
  148. Term = Convert.ToInt32(data["num"].Value),
  149. OpenCode1 = Convert.ToInt32(data["one"].Value),
  150. OpenCode2 = Convert.ToInt32(data["two"].Value),
  151. OpenCode3 = Convert.ToInt32(data["three"].Value),
  152. OpenCode4 = Convert.ToInt32(data["four"].Value),
  153. OpenCode5 = Convert.ToInt32(data["five"].Value),
  154. OpenCode6 = Convert.ToInt32(data["six"].Value),
  155. OpenCode7 = Convert.ToInt32(data["seven"].Value),
  156. OpenTime = Convert.ToDateTime(OpenTime),
  157. DetailUrl = string.Format(
  158. "http://www.js-lottery.com/Article/news/group_id/3/article_id/{0}.html",
  159. data["article_id"].Value)
  160. });
  161. }
  162. pageIndex++;
  163. }
  164. var checkDataHelper = new CheckDataHelper();
  165. var dbdata = services.GetListS<OpenCode7DTModel>(currentLottery)
  166. .ToDictionary(w => w.Term.ToString(), w => w.GetCodeStr());
  167. checkDataHelper.CheckData(dbdata, result.ToDictionary(w => w.Term.ToString(), w => w.GetCodeStr()),
  168. Config.Area, currentLottery);
  169. result = result.OrderByDescending(S => S.Term).ToList();
  170. }
  171. catch (Exception ex)
  172. {
  173. log.Error(typeof(JSTC7WSJob),
  174. string.Format("【{0}】通过主站点抓取开奖列表时发生错误,错误信息【{1}】", Config.Area + currentLottery, ex.Message));
  175. }
  176. return result;
  177. }
  178. /// <summary>
  179. /// 完善主站江苏体彩7位数开奖详情信息
  180. /// </summary>
  181. /// <param name="model"></param>
  182. private bool OptimizeBackModel(ref OpenCode7DTModel model, HtmlNode tr)
  183. {
  184. try
  185. {
  186. var entity = new KaijiangDetailsEntity();
  187. entity.KaiJiangItems = new List<Kaijiangitem>();
  188. var tds = tr.ChildNodes.Where(w => w.Name == "td").ToList();
  189. var xiaoshoue = tds[2].InnerText.Trim().Replace(",", "").Replace("元", "");
  190. var jiangchi = "";
  191. var tedengjiang = new Kaijiangitem
  192. {
  193. Name = "特等奖",
  194. Total = tds[3].InnerText.Trim(),
  195. TotalMoney = tds[4].InnerText
  196. };
  197. entity.KaiJiangItems.Add(tedengjiang);
  198. var yidengjiang = new Kaijiangitem
  199. {
  200. Name = "一等奖",
  201. Total = tds[5].InnerText.Trim(),
  202. TotalMoney = tds[6].InnerText
  203. };
  204. entity.KaiJiangItems.Add(yidengjiang);
  205. var erdengjiang = new Kaijiangitem
  206. {
  207. Name = "二等奖",
  208. Total = tds[7].InnerText.Trim(),
  209. TotalMoney = tds[8].InnerText
  210. };
  211. entity.KaiJiangItems.Add(erdengjiang);
  212. entity.Gdje = jiangchi;
  213. entity.Trje = xiaoshoue;
  214. model.Spare = entity.TryToJson();
  215. }
  216. catch (Exception ex)
  217. {
  218. log.Error(typeof(JSTC7WSJob),
  219. string.Format("【{0}】通过主站点优化开奖列表时发生错误,错误信息【{1}】", Config.Area + currentLottery, ex.Message));
  220. }
  221. return false;
  222. }
  223. /// <summary>
  224. /// 完善主站江苏体彩7位数开奖详情信息
  225. /// </summary>
  226. /// <param name="model"></param>
  227. private bool OptimizeMainModel(ref OpenCode7DTModel model)
  228. {
  229. try
  230. {
  231. var entity = new KaijiangDetailsEntity();
  232. entity.KaiJiangItems = new List<Kaijiangitem>();
  233. var htmlResource = NetHelper.GetUrlResponse(model.DetailUrl);
  234. if (htmlResource == null) return false;
  235. if (!string.IsNullOrEmpty(htmlResource))
  236. {
  237. var doc = new HtmlDocument();
  238. doc.LoadHtml(htmlResource);
  239. var table = doc.DocumentNode.SelectNodes("//table");
  240. if (table != null && table.Count > 1)
  241. {
  242. var trs = table[1].ChildNodes.Where(N => N.Name.ToLower() == "tbody").First().ChildNodes
  243. .Where(N => N.Name.ToLower() == "tr").ToList();
  244. for (var i = 0; i < trs.Count; i++)
  245. {
  246. var tds = trs[i].ChildNodes.Where(N => N.Name.ToLower() == "td").ToList();
  247. if (tds[0].InnerText == "特等奖")
  248. {
  249. var tmp = new Kaijiangitem
  250. {
  251. Name = "特等奖",
  252. Total = tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty),
  253. TotalMoney =
  254. tds[2].InnerText.Replace("元", string.Empty).Replace("--", "0").Replace(",", "")
  255. .Trim()
  256. };
  257. entity.KaiJiangItems.Add(tmp);
  258. //Level1Num = Convert.ToInt32(tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty));
  259. //Level1Money = Convert.ToDecimal(tds[2].InnerText.Replace("元", string.Empty));
  260. }
  261. else if (tds[0].InnerText == "一等奖")
  262. {
  263. var tmp = new Kaijiangitem
  264. {
  265. Name = "一等奖",
  266. Total = tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty),
  267. TotalMoney =
  268. tds[2].InnerText.Replace("元", string.Empty).Replace("--", "0").Replace(",", "")
  269. .Trim()
  270. };
  271. entity.KaiJiangItems.Add(tmp);
  272. }
  273. else if (tds[0].InnerText == "二等奖")
  274. {
  275. var tmp = new Kaijiangitem
  276. {
  277. Name = "二等奖",
  278. Total = tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty),
  279. TotalMoney =
  280. tds[2].InnerText.Replace("元", string.Empty).Replace("--", "0").Replace(",", "")
  281. .Trim()
  282. };
  283. entity.KaiJiangItems.Add(tmp);
  284. }
  285. else if (tds[0].InnerText == "三等奖")
  286. {
  287. var tmp = new Kaijiangitem
  288. {
  289. Name = "三等奖",
  290. Total = tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty),
  291. TotalMoney =
  292. tds[2].InnerText.Replace("元", string.Empty).Replace("--", "0").Replace(",", "")
  293. .Trim()
  294. };
  295. entity.KaiJiangItems.Add(tmp);
  296. }
  297. else if (tds[0].InnerText == "四等奖")
  298. {
  299. var tmp = new Kaijiangitem
  300. {
  301. Name = "四等奖",
  302. Total = tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty),
  303. TotalMoney =
  304. tds[2].InnerText.Replace("元", string.Empty).Replace("--", "0").Replace(",", "")
  305. .Trim()
  306. };
  307. entity.KaiJiangItems.Add(tmp);
  308. }
  309. else if (tds[0].InnerText == "五等奖")
  310. {
  311. var tmp = new Kaijiangitem
  312. {
  313. Name = "五等奖",
  314. Total = tds[1].InnerText.Replace(",", string.Empty).Replace("注", string.Empty),
  315. TotalMoney =
  316. tds[2].InnerText.Replace("元", string.Empty).Replace("--", "0").Replace(",", "")
  317. .Trim()
  318. };
  319. entity.KaiJiangItems.Add(tmp);
  320. }
  321. }
  322. var reg1 = new Regex(@"本省(区、市)销售额:([\s\S]*?)元");
  323. var match1 = reg1.Match(htmlResource);
  324. if (match1.Success)
  325. {
  326. //2016年182期及以前期数
  327. //Sales = Convert.ToDecimal(match1.Result("$1"));
  328. entity.Trje = match1.Result("$1");
  329. }
  330. else
  331. {
  332. //2016年183期及以后期数
  333. reg1 = new Regex(@"本期销售金额:([\s\S]*?)元");
  334. match1 = reg1.Match(htmlResource);
  335. if (match1.Success) entity.Trje = match1.Result("$1");
  336. }
  337. var ps = table[1].ParentNode.ChildNodes.Where(N => N.Name.ToLower() == "p").ToList();
  338. var potString = ps.Last().InnerHtml;
  339. reg1 = new Regex(@"<br>([\s\S]*?)元");
  340. match1 = reg1.Match(potString);
  341. if (match1.Success)
  342. {
  343. var potValue = match1.Result("$1").Replace("&nbsp;", string.Empty);
  344. if (potValue.Contains("<br>"))
  345. // Jackpot = Convert.ToDecimal(potValue.Substring(potValue.IndexOf("<br>") + 4));
  346. entity.Gdje = potValue.Substring(potValue.IndexOf("<br>") + 4);
  347. else
  348. // Jackpot = Convert.ToDecimal(potValue);
  349. entity.Gdje = potValue;
  350. }
  351. model.Spare = entity.TryToJson();
  352. return true;
  353. }
  354. }
  355. }
  356. catch (Exception ex)
  357. {
  358. log.Error(typeof(JSTC7WSJob),
  359. string.Format("【{0}】通过主站点优化开奖列表时发生错误,错误信息【{1}】", Config.Area + currentLottery, ex.Message));
  360. }
  361. return false;
  362. }
  363. /// <summary>
  364. /// 通过备用站点抓取开奖数据
  365. /// (百度乐彩)
  366. /// </summary>
  367. private void DoBackUrl()
  368. {
  369. if (!string.IsNullOrEmpty(Config.BackUrl))
  370. {
  371. var OpenList = GetOpenListFromBackUrl();
  372. if (OpenList.Count == 0) return; //无抓取数据
  373. var newestQiHao = OpenList.First().Term.ToString();
  374. var startQiNum = Convert.ToInt32(LatestItem.Term.ToString().Substring(2)) + 1;
  375. var newestQiNum = Convert.ToInt32(newestQiHao.Substring(2));
  376. if (startQiNum > newestQiNum) return; //无最新数据
  377. //处理最新开奖数据
  378. var getQiHao = string.Empty;
  379. OpenCode7DTModel matchItem = null;
  380. for (var i = startQiNum; i <= newestQiNum; i++)
  381. {
  382. getQiHao = LatestItem.Term.ToString().Substring(0, 2) + i.ToString().PadLeft(3, '0');
  383. matchItem = OpenList.Where(R => R.Term.ToString() == getQiHao).FirstOrDefault();
  384. if (matchItem != null && services.AddDTOpen7Code(currentLottery, matchItem))
  385. {
  386. //Do Success Log
  387. log.Info(typeof(JSTC7WSJob), CommonHelper.GetJobBackLogInfo(Config, getQiHao));
  388. LatestItem = matchItem;
  389. isGetData = true;
  390. }
  391. }
  392. }
  393. }
  394. private List<OpenCode7DTModel> GetOpenListFromBackUrl()
  395. {
  396. var result = new List<OpenCode7DTModel>();
  397. try
  398. {
  399. var url = Config.BackUrl + "?lid=10048&page=1";
  400. var htmlResource = NetHelper.GetBaiDuLeCaiResponse(url);
  401. if (htmlResource == null) return result;
  402. var doc = new HtmlDocument();
  403. doc.LoadHtml(htmlResource);
  404. var table = doc.DocumentNode.SelectSingleNode("//table");
  405. if (table == null) return result;
  406. var trs = table.ChildNodes.Where(node => node.Name == "tr").ToList();
  407. trs.RemoveAll(w => w.GetAttributeValue("class", "") != "");
  408. foreach (var item in trs)
  409. {
  410. var tds = item.ChildNodes.Where(w => w.Name == "td").ToList();
  411. var qihao = tds[0].InnerText.Trim().Substring(2);
  412. var kaijianghao = tds[1].InnerText.Trim();
  413. var opentime = tds[9].InnerText.Trim();
  414. var tmp = new OpenCode7DTModel
  415. {
  416. Term = long.Parse(qihao),
  417. OpenTime = DateTime.Parse(opentime)
  418. };
  419. tmp.OpenCode1 = int.Parse(kaijianghao.Substring(0, 1));
  420. tmp.OpenCode2 = int.Parse(kaijianghao.Substring(1, 1));
  421. tmp.OpenCode3 = int.Parse(kaijianghao.Substring(2, 1));
  422. tmp.OpenCode4 = int.Parse(kaijianghao.Substring(3, 1));
  423. tmp.OpenCode5 = int.Parse(kaijianghao.Substring(4, 1));
  424. tmp.OpenCode6 = int.Parse(kaijianghao.Substring(5, 1));
  425. tmp.OpenCode7 = int.Parse(kaijianghao.Substring(6, 1));
  426. OptimizeBackModel(ref tmp, item);
  427. result.Add(tmp);
  428. }
  429. var checkDataHelper = new CheckDataHelper();
  430. var dbdata = services.GetListS<OpenCode7DTModel>(currentLottery)
  431. .ToDictionary(w => w.Term.ToString(), w => w.GetCodeStr());
  432. checkDataHelper.CheckData(dbdata, result.ToDictionary(w => w.Term.ToString(), w => w.GetCodeStr()),
  433. Config.Area, currentLottery);
  434. result = result.OrderByDescending(S => S.Term).ToList();
  435. }
  436. catch (Exception ex)
  437. {
  438. log.Error(typeof(JSTC7WSJob),
  439. string.Format("【{0}】通过备用站点抓取开奖列表时发生错误,错误信息【{1}】", Config.Area + currentLottery, ex.Message));
  440. }
  441. return result;
  442. }
  443. #region Attribute
  444. /// <summary>
  445. /// 配置信息
  446. /// </summary>
  447. private SCCConfig Config;
  448. /// <summary>
  449. /// 当天抓取的最新一期开奖记录
  450. /// </summary>
  451. private OpenCode7DTModel LatestItem;
  452. /// <summary>
  453. /// 当天抓取失败列表
  454. /// </summary>
  455. private List<string> FailedQiHaoList = null;
  456. /// <summary>
  457. /// 日志对象
  458. /// </summary>
  459. private readonly LogHelper log;
  460. /// <summary>
  461. /// 数据服务
  462. /// </summary>
  463. private readonly IDTOpenCode services;
  464. /// <summary>
  465. /// 当前彩种
  466. /// </summary>
  467. private SCCLottery currentLottery => SCCLottery.JiangSuTC7WS;
  468. /// <summary>
  469. /// 邮件接口
  470. /// </summary>
  471. private IEmail email;
  472. /// <summary>
  473. /// 是否本次运行抓取到开奖数据
  474. /// </summary>
  475. private bool isGetData;
  476. #endregion
  477. }
  478. }