c# 模擬 網頁實現12306登陸、自動刷票、自動搶票完全篇(轉)


這一篇文章,我將從頭到尾教大家使用c#模擬網頁面登陸12306網站,自動刷票,選擇訂票人,到最后一步提交訂單。研究過HTTP協議的童鞋們都 知道,我們在訪問網站時,是有兩種方式的,POST和GET方式,HTTP協議是TCP/IP的一部分,有興趣的可以使用Socket通訊可以模擬出 HTTP的訪問機制。我們再說POST和GET方式,在訪問一個頁面時,瀏覽器會提交一個本地cookie提交到網站服務器,cookie的作用可以是保 存我們登陸網站成功后取得的一串鑰匙,也可以是其他的一些重要的信息。這是至關重要的一步。讓我們步入正題。

我們來了解12306的登陸方式,我們使用http跟蹤發現他的登陸的地址

https://kyfw.12306.cn/otn/login/loginAysnSuggest

 

在登陸過過程中提交了一個表單數據,包括loginserDTO.user_name、userDTO.password、randCode。我第一次看見時都有點悲催了,這么一個大的網站,密碼傳輸竟然是明文的..

第一個參數是我們的用戶名、第二是密碼、第三個是校驗碼。

接下來我們要做的就是獲取登陸驗證碼了。我們看到驗證碼的地址是

 

這是一個圖片的地址,我們將這個圖片地址指向我們的picturebox控件的Image路徑。最終的登陸界面是這樣的

新建一個HttpWebRequestExtension.cs 類,加入我們核心代碼,包括提交訂單數據,獲取網頁內容,獲取校驗碼圖片。

復制代碼
/// <summary> /// 模擬網頁操作,提交、獲取訂單頁面數據 /// </summary> public class HttpWebRequestExtension { private static string contentType = "application/x-www-form-urlencoded"; private static string accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight-2-b1, */*"; private static string userAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Zune 4.7; BOIE9;ZHCN)"; private static string referer = "https://kyfw.12306.cn/"; /// <summary> /// 提交訂單數據 /// </summary> /// <param name="url"></param> /// <param name="cookie"></param> /// <param name="param"></param> /// <returns></returns> public static string PostWebContent(string url, CookieContainer cookie, string param) { byte[] bs = Encoding.ASCII.GetBytes(param); var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.CookieContainer = cookie; httpWebRequest.ContentType = contentType; httpWebRequest.Accept = accept; httpWebRequest.UserAgent = userAgent; httpWebRequest.Method = "POST"; httpWebRequest.ContentLength = bs.Length; using (Stream reqStream = httpWebRequest.GetRequestStream()) { reqStream.Write(bs, 0, bs.Length); } var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string html = streamReader.ReadToEnd(); streamReader.Close(); responseStream.Close(); httpWebRequest.Abort(); httpWebResponse.Close(); return html; } /// <summary> /// 獲取頁面數據 /// </summary> /// <param name="url"></param> /// <param name="cookie"></param> /// <returns></returns> public static string GetWebContent(string url, CookieContainer cookie) { var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.CookieContainer = cookie; httpWebRequest.ContentType = contentType; httpWebRequest.Referer = referer; httpWebRequest.Accept = accept; httpWebRequest.UserAgent = userAgent; httpWebRequest.Method = "GET"; httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue; var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string html = streamReader.ReadToEnd(); streamReader.Close(); responseStream.Close(); httpWebRequest.Abort(); httpWebResponse.Close(); return html; } /// <summary> /// 獲取網頁驗證碼圖片 /// </summary> /// <param name="url"></param> /// <param name="cookie"></param> /// <returns></returns> public static object GetWebImage(string url, CookieContainer cookie) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Referer = referer; request.UserAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"; request.Accept = "image/webp,*/*;q=0.8"; request.CookieContainer = cookie; request.ContentType = contentType; request.KeepAlive = true; request.UseDefaultCredentials = true; // request.Proxy = null; return request.GetResponse().GetResponseStream(); } }
復制代碼

 

然后我們就可以模擬登陸12306了。

var loginRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.AsynSugguestUrl, cookieContainer, "loginUserDTO.user_name=" + userLogin.UserName + "&&userDTO.password=" + userLogin.Password + "&&randCode=" + userLogin.VerifyCode );

 

 

登陸的結果是以JSON數據格式返回的。如果你看到有 loginCheck\":\"Y\",那么恭喜,你已經登陸上網站了。

如果失敗了也無妨,返回的結果可以看到登陸失敗的原因,message:[“..”], ...表示返回的錯誤原因,這里就不一一列出了。

 

注意:登陸成功后保存cookie的狀態,前面強調過這是最重要的一個環節。

 

然后獲取車站信息。車站信息保存在一個JS里面,我們需要解碼JS。

https://kyfw.12306.cn/otn/resources/js/framework/station_name.js

 

大家使用瀏覽器打開看看,里面是不是一個定義好的以|分隔的車站信息,我們只需要提取出車站名稱和車站編碼。以下是我的解碼方式。

 

[csharp]  view plain copy
 
    1. var s = station.Split('=')[1].Replace("'", "").Replace(";", "").Split('|'); for (int i = 0; i < s.Length; i++) { if (i % 5 == 0) { if ((i + 1) < s.Length && (i + 4) < s.Length) { string statename = s[i + 1]; string code = s[i + 2]; cacheDic.Add(statename, code); cmbstartStation.Items.Add(statename); cmbendStation.Items.Add(statename); } } }  

 

再進一下獲取購票人信息,我們的聯系人的URL是 https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs,這是一個JSON數據。

 

 

JSON數據里面包含有所有聯系人的信息內容,包括電話、身份證號、出生年月、是否學生、性別等。有了這些基礎數據我們就可以刷票、購票了。讓我們先看看剩余的票數吧

https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={0}&leftTicketDTO.from_station={1}&leftTicketDTO.to_station={2}&purpose_codes=ADULT

 

URL里面傳遞的數據有始發站、終點站、出發日期等信息。 我們使用Get 方式獲取余票信息

 var url = string.Format(TrainUrlConstant.TrainleftTicketInfo, startTime, from, to); var trainleftTicketInfoRes = HttpWebRequestExtension.GetWebContent(url, cookieContainer);

 

 

返回的JSON數據里面包含有車票的標志位,也就是上圖的secretStr,還有出發時間、軟卧數、硬卧數、軟座、硬座數等。

有了這些數據 我們就可以選擇自動刷票了。

 

 

 

接下來選定好坐席,車次開始搶票。

選中車次后 確認提交我們選中的車次信息,我們看一下他需要傳的參數信息

 

 

[csharp]  view plain copy
 
  1. var param = "secretStr=" + selectedTrainView.SrcetStr + "&train_date=" + selectedTrainView.Time + "&back_train_date=" + selectedTrainView.TotalTime + "&tour_flag=dc&purpose_codes=ADULT&query_from_station_name=" + selectedTrainView.From + "&query_to_station_name=" + selectedTrainView.To + ""; var confirmParmRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.SubmitOrderPredicateUrl, cookieContainer, param);  

 

 

 

12306提交訂單使用的是一個訂單一個隨機的token信息,那么在這之前我們就必須先要獲取Token信息了

 

那么這個表單里面的token、key_check_ischange、leftTicketStr、train_location從哪里來呢?這 就到了考驗耐心的時候了,經過仔細的查找發現,原來這些信息是隱藏在網頁的JS里面。頁面地址是 https://kyfw.12306.cn/otn/confirmPassenger/initDc 不仔細看還真看不出來啊。

  

var submitPassagerRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.SubmitOrderInitialUrl, cookieContainer, "_json_att="); 

 

 

 

 

另外兩個參數passengerTicketStr、oldPassengerStr 是我們選中購票人,仔細分析這串字符串,發現其中是有規律的,每一個購票人是以_分隔的。逗號前第一個數據代表的是座席號,逗號的第四個數據是聯系人,記 住需要用URL編碼格式,第6個是身份證號,第7個是手機號。

然后再獲取提交訂單前的校驗碼 https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=passenger&rand=randp

pbxOrderCode.Image = Image.FromStream((Stream)HttpWebRequestExtension.GetWebImage(TrainUrlConstant.OrderValidateCodeUrl, cookie));

 

 

將我們上面找出來的表單信息提交到網站校驗是不是有問題

 

 

[csharp]  view plain copy
 
    1. param = @"cancel_flag=2&bed_level_order_num=000000000000000000000000000000&" + selectedticketcontacts + "&" + selectedoldpasswordticketcontacts + "&tour_flag=dc&randCode=" + verifyCode + "&_json_att=&REPEAT_SUBMIT_TOKEN=" + token.Trim(); var checkOrderRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.CheckOrderUrl, cookieContainer, param); var checkOrderRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.CheckOrderUrl, cookieContainer, param); if (checkOrderRes != null && checkOrderRes.IndexOf("系統忙") > 0) { return; }  

 

正確的訂單返回的結果

 

 

如果以上都沒有問題的話,接下來就可以進入到真正意義的搶票過程了。我們看一下搶票的URL

https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue

 

 

[csharp]  view plain copy
 
    1. param = selectedticketcontacts + "&" + selectedoldpasswordticketcontacts + "&randCode=" + verifyCode + "&purpose_codes=00&key_check_isChange=" + key_check + "&leftTicketStr=" + lefttick.Trim() + "&train_location=" + train_location + "&_json_att=&REPEAT_SUBMIT_TOKEN=" + token.Trim() + ""; var confirmOrderRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.ConfirmOrderUrl, cookieContainer, param); var errorMsg = string.Empty; Regex.Replace(submitPassagerRes, "(errMsg).*,", new MatchEvaluator(p => { if (p.Value.IndexOf("errMsg") >= 0) { errorMsg = p.Value.Substring(0, p.Value.IndexOf(",")); errorMsg = errorMsg.Replace("errMsg", "").Replace("'", "").Replace("=", "").Replace(";", "").Replace(",", "").Replace(":", ""); } return null; }));  

 

就差最后一步了。我們看看是不是生成訂單號了。

 

[csharp]  view plain copy
 
  1. //等待訂單完成 var waitorderurl = string.Format(TrainUrlConstant.WaitOrderStateUrl, j, token); int id = 0; var ultimateRes = HttpWebRequestExtension.GetWebContent(waitorderurl, cookieContainer);  



 

看看返回的JSON結果里面有沒有orderID,當orderID大於0,表示你的票已經搶到手了。趕緊登陸網站付款去吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM