這一篇文章,我將從頭至尾教你們使用c#模擬網頁面登錄12306網站,自動刷票,選擇訂票人,到最後一步提交訂單。研究過HTTP協議的童鞋們都 知道,咱們在訪問網站時,是有兩種方式的,POST和GET方式,HTTP協議是TCP/IP的一部分,有興趣的可使用Socket通信能夠模擬出 HTTP的訪問機制。咱們再說POST和GET方式,在訪問一個頁面時,瀏覽器會提交一個本地cookie提交到網站服務器,cookie的做用能夠是保 存咱們登錄網站成功後取得的一串鑰匙,也能夠是其餘的一些重要的信息。這是相當重要的一步。讓咱們步入正題。html
咱們來了解12306的登錄方式,咱們使用http跟蹤發現他的登錄的地址web
https://kyfw.12306.cn/otn/login/loginAysnSuggestjson
在登錄過過程當中提交了一個表單數據,包括loginserDTO.user_name、userDTO.password、randCode。我第一次看見時都有點悲催了,這麼一個大的網站,密碼傳輸居然是明文的..c#
第一個參數是咱們的用戶名、第二是密碼、第三個是校驗碼。瀏覽器
接下來咱們要作的就是獲取登錄驗證碼了。咱們看到驗證碼的地址是服務器
這是一個圖片的地址,咱們將這個圖片地址指向咱們的picturebox控件的Image路徑。最終的登錄界面是這樣的cookie
新建一個HttpWebRequestExtension.cs 類,加入咱們核心代碼,包括提交訂單數據,獲取網頁內容,獲取校驗碼圖片。app
/// <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了。ide
var loginRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.AsynSugguestUrl, cookieContainer, "loginUserDTO.user_name=" + userLogin.UserName + "&&userDTO.password=" + userLogin.Password + "&&randCode=" + userLogin.VerifyCode );
登錄的結果是以JSON數據格式返回的。若是你看到有 loginCheck\":\"Y\",那麼恭喜,你已經登錄上網站了。post
若是失敗了也無妨,返回的結果能夠看到登錄失敗的緣由,message:[「..」], ...表示返回的錯誤緣由,這裏就不一一列出了。
注意:登錄成功後保存cookie的狀態,前面強調過這是最重要的一個環節。
而後獲取車站信息。車站信息保存在一個JS裏面,咱們須要解碼JS。
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js
你們使用瀏覽器打開看看,裏面是否是一個定義好的以|分隔的車站信息,咱們只須要提取出車站名稱和車站編碼。如下是個人解碼方式。
再進一下獲取購票人信息,咱們的聯繫人的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,還有出發時間、軟臥數、硬臥數、軟座、硬座數等。
有了這些數據 咱們就能夠選擇自動刷票了。
接下來選定好坐席,車次開始搶票。
選中車次後 確認提交咱們選中的車次信息,咱們看一下他須要傳的參數信息
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));
將咱們上面找出來的表單信息提交到網站校驗是否是有問題
正確的訂單返回的結果
若是以上都沒有問題的話,接下來就能夠進入到真正意義的搶票過程了。咱們看一下搶票的URL
https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue
就差最後一步了。咱們看看是否是生成訂單號了。
看看返回的JSON結果裏面有沒有orderID,當orderID大於0,表示你的票已經搶到手了。趕忙登錄網站付款去吧。