今天又到了搶火車票的時候,反正是每次搶票都是傻眼。於是寫個小工具幫助自己查詢火車票,如果有票的話給自己發個郵件提示購買。
一、准備工作
利用firebug等工具,我們可以獲取到當我們單擊查詢時調用的Get請求。
接下來我們要對返回的json進行分析,返回的json如下:
{
"validateMessagesShowId": "_validatorMessage",
"status": true,
"httpstatus": 200,
"data": {
"result": [
"oSIL3O3WIe6kfzF42Zlz%2B%2BsPFUuDm4BbNP13vXPnMnwSVXDgZ03onlMGao1RqJYjWimJDOiBa9Xm%0A59BctbygQhG6xM5mfTPPb9dLuvYg43VQYKGBpYzHere%2B4diEqyOfA64i6OcUFpe8ZJ4ccCEiQK7d%0AsFWdn6qDxY5PDQ2zG%2BCCNeAG216PdgO%2Fv%2F0PIrQTTK%2FTft8oZIxGT9VYlkHeh3TUUdxenyGAts4J%0AJ278LrM%3D|預訂|260000Y5160F|Y516|VVP|ZMP|TXP|XHP|12:46|19:00|06:14|Y|rC9CEREwzGPqGayEjfr9YPwYtGX%2B45X6aKXyL0VaY0Bauu4t|20170901|3|P2|11|19|0|0|||||無||有|||有|||||101020|112",
"wIpyiHG7PkQUnuOjE7gTxQAW39ihKOVttmAMx1lyhE10OyzjXjCe0EzyOsu28FOvw0Yc6CZF4CAQ%0AhR6L%2BAgyc6ca%2FYubiLZ4HuKw%2B0XmN5Us9fmA%2FajP3P%2FZgSoacqyPHPXEhWZ8pfGWSkmLMRNpisgd%0A48kWkp8rhjVIDljoncMagr6t5il3t5FaP8otqcN4ZtnTL1KfslpZt%2B2gxw7GwNFZH0QGTq2uoIuu%0AnYTSCB11w3Ok|預訂|25000011360J|1136|TJP|WXC|TJP|XHP|20:52|01:55|05:03|Y|ZhbR6hnByAgL1ejqxJ1AIYiWcW2q08ZgO%2Bfk6UjtmX5mYLHGGlNBCiPVZDc%3D|20170901|3|P2|01|04|0|0||||無|||有||無|無|||||10401030|1413",
"yG8TT6qCWjH0Aa2LVzxfCFGHf2q0syxOx7RfcXmsbFNyfq2VlWOS3q0oODd5tWAY2I5ddZfSBvnl%0A1GT%2BQCpZAhTPSLyRfDKCvwNMykAFe%2BuRULRPxd1WsQ57uIWepqDtElMcpGR8m7HB6KTnlzXXL9te%0AkumIJNMRMtA0ukPZto5G3sOGSSHgmQdcAxRmRdCVBFEsS9dNprjSQBwy%2BsxXq7KfAovJcemtY%2B3H%0AC7Kx4hnW5HXZ|預訂|250000K8880H|K888|TJP|XNO|TJP|XHP|21:38|02:38|05:00|Y|uwEONiPztkLymI5okpF%2FJhWo7bzZA1zPcjbuofQXIXLCubD2gxSlXoz8nI8%3D|20170901|3|PB|01|04|0|0||||無|||有||無|有|||||10401030|1413"
],
"flag": "1",
"map": {
"TXP": "天津西",
"XHP": "宣化",
"TJP": "天津"
}
},
"messages": [],
"validateMessages": {}
}
網頁顯示:
好了我們的准備工作差不多就這樣了。
二、編寫代碼
現在的任務就是數據的獲取,代碼如下:
/// <summary> /// 車票查詢數據獲取 /// </summary> /// <param name="goTime">出行日期</param> /// <param name="fromStationCode">出發站編碼</param> /// <param name="toStationCode">到達站編碼</param> /// <param name="errorMsg">錯誤消息</param> /// <returns></returns> public TicketSearchJson GetSearchTicketData(DateTime goTime, string fromStationCode, string toStationCode, ref string errorMsg) { string srcString = string.Empty; try { using (WebClient client = new WebClient()) { string url = string.Format("https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={0}&leftTicketDTO.from_station={1}&leftTicketDTO.to_station={2}&purpose_codes=ADULT", goTime.ToString("yyyy-MM-dd"), fromStationCode, toStationCode); Uri uri = new Uri(url); ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; byte[] responseData = client.DownloadData(uri); srcString = Encoding.UTF8.GetString(responseData); TicketSearchJson ticketSearch = JsonConvert.DeserializeObject<TicketSearchJson>(srcString); return ticketSearch; } } catch (Exception ex) { errorMsg = ex.Message; return null; } } /// <summary> /// 服務器證書回調方法 /// </summary> /// <param name="sender"></param> /// <param name="certificate"></param> /// <param name="chain"></param> /// <param name="sslPolicyErrors"></param> /// <returns></returns> private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; }
郵件發送功能可見這篇博客:小工具:郵件發送
三、運行截圖
切勿過於頻繁調用接口!!!
程序下載:https://pan.baidu.com/s/1hrC2CPQ
四、更新
2018.1.2 獲取數據后解析亂碼問題
分析后得知 響應數據經過壓縮:Content-Encoding: gzip
解決方法(加粗代碼):
1 public TicketSearchJson GetSearchTicketData_WebRequest(DateTime goTime, string fromStationCode, string toStationCode, ref string errorMsg) 2 { 3 string srcString = string.Empty; 4 if (string.IsNullOrEmpty(fromStationCode) || string.IsNullOrEmpty(toStationCode)) { errorMsg = "出發站編碼、到達站編碼不能為空"; return null; } 5 if (fromStationCode == toStationCode) { errorMsg = "出發站和到達站不能相同!"; return null; } 6 try 7 { 8 string url = string.Empty; 9 try 10 { 11 url = string.Format(System.Configuration.ConfigurationManager.AppSettings["Url"].ToString(), 12 goTime.ToString("yyyy-MM-dd"), fromStationCode, toStationCode); 13 } 14 catch { LogHelper.WriteErrorLog("讀取url失敗!"); } 15 Uri uri = new Uri(url); 16 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); 17 string cookie = string.Empty; 18 try { cookie = CreateCookie(fromStationCode, toStationCode); } 19 catch { LogHelper.WriteInfoLog("讀取Cookie失敗!"); errorMsg = "讀取Cookie失敗!"; } 20 HttpWebRequestHelper.SetRequestHeader(request, "kyfw.12306.cn", cookie); 21 ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; 22 WebResponse response = request.GetResponse(); 23 Stream respStream = response.GetResponseStream(); 24 //如果響應頭中包含Content-Encoding: gzip 數據需要解壓縮 25 bool isNeedDeCompress = response.Headers.ToString().Contains("Content-Encoding: gzip"); 26 if (isNeedDeCompress) 27 respStream = new GZipStream(respStream, CompressionMode.Decompress); 28 using (StreamReader reader = new StreamReader(respStream, Encoding.UTF8)) 29 { 30 srcString = reader.ReadToEnd(); 31 if (srcString.Contains("!DOCTYPE html")) 32 { 33 errorMsg = "網絡可能存在問題,請您重試一下!"; 34 return null; 35 } 36 } 37 TicketSearchJson ticketSearch = JsonConvert.DeserializeObject<TicketSearchJson>(srcString); 38 return ticketSearch; 39 } 40 catch (Exception ex) 41 { 42 errorMsg = ex.Message; 43 LogHelper.WriteErrorLog("數據獲取異常:" + ex.Message); 44 return null; 45 } 46 }