C#利用HttpWebRequest、HttpWebResponse調用12306接口,實現登錄、查票、買票。

【免責申明】本文只爲學習使用,若有用作商業、其他行爲,與本人無關。
使用工具
- UI bootstrap
- 後臺C#
- 插件 datetimepicker.js,select.js


UI界面效果預覽

這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述

UI界面源碼


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">

    <title>火車搶票系統</title>
    <link href="css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/bootstrap-datetimepicker.min.css" rel="stylesheet" />
    <link href="css/bootstrap-select.min.css" rel="stylesheet" />
    <style>
        body{
            width:90%;
            margin:0 5%;
        }
        table th{
            text-align:center;
        }
        td{
            text-align:center; 
        }

    </style>
</head>
<body>
    <nav class="navbar navbar-default ">
        <div class="container-fluid">
            <p class="navbar-text navbar-right" style="padding-right:5%;"> <a href="#" class="navbar-link" onclick="Login()"> 登錄 </a><a href="#" class="navbar-link" onclik="LoginOut()"> 退出 </a></p>
        </div>
    </nav>
    <form class="form-horizontal" >
        <div class="form-group">
           <label class="col-md-1 control-label">出發地</label> 
            <div class="col-md-2">
                <select class="selectpicker" data-live-search="true" id="FromStation">

                </select>
            </div>
            <label class="col-md-1 control-label">目的地</label>
            <div class="col-md-2 ">
                <select class="selectpicker" data-live-search="true" id="ToStation">
                </select>
            </div>
            <label class="col-md-1 control-label">出發日</label>
            <div class="col-md-2">
                <input type="text" class="form-control" id="txtTranDate" placeholder="請輸入出發日期">
            </div>
            <div class="col-md-3">
                <button type="button" class="btn btn-primary " id="btnSearch">查詢</button>
            </div>
        </div>
    </form>
    <div>
        <table class="table table-bordered table-hover" >
           <thead style="background-color:turquoise"><tr><th>車次</th><th>出發站<br />到達站</th><th>出發時間<br />到達時間</th><th>歷時</th><th>商務座<br />特等座</th><th>一等座</th><th>二等座</th><th>高級<br />軟臥</th><th>軟臥</th><th>動臥</th><th>硬臥</th><th>軟座</th><th>硬座</th><th>無座</th><th>其他</th><th>備註</th></tr></thead>
            <tbody id="tbTranContent"></tbody>
        </table>
    </div>
    <script src="scripts/jquery-1.11.1.min.js"></script>
    <script src="scripts/bootstrap.min.js"></script>

    <script src="scripts/bootstrap-datetimepicker.min.js" ></script>
    <script src="scripts/locales/bootstrap-datetimepicker.zh-CN.js" charset="utf-8"></script>

    <script src="scripts/bootstrap-select.min.js"></script>
    <script src="scripts/layer/layer.js"></script>

    <script src="scripts/index.js"></script>
</body>

</html>

後臺

主要的功能查詢火車票、查詢到站信息、查詢價格、獲取驗證碼、校驗驗證碼、校驗密碼

主要的技術還是利用HttpWebRequest、HttpWebResponse來調用12306的接口。

登錄界面

這裏寫圖片描述

 獲取驗證碼接口:
調用的12306的接口獲取文件流,然後出入二進制流。

 void GetValidateImg(HttpContext context)
        {
            #region 獲取登錄驗證碼
            string url = "https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand";

            Stream stream = GetStreamByGet(url);
            if (stream != null)
            {
                List<byte> bytes = new List<byte>();
                int i = stream.ReadByte();
                while (i != -1)
                {
                    bytes.Add((byte)i);
                    i = stream.ReadByte();
                }

                context.Response.Clear();
                context.Response.ContentType = "image/jpeg";
                context.Response.BinaryWrite(bytes.ToArray());

            }
            #endregion
        }

校驗驗證碼:12306的驗證碼是290px*190px的圖片,每個照片分爲8個小的圖片。12306根據點擊小圖片的相對座標。例如第二張小圖片相對於整張的座標(左上角爲0,0)爲50,90,。到時候post請求時候帶的參數就是answer=50,90。

  void ValidateCode(HttpContext context)
        {
            #region 校驗驗證碼
            string answer = "";
            if (!string.IsNullOrEmpty(context.Request["answer"]))
                answer = context.Request["answer"];

            string url = "https://kyfw.12306.cn/passport/captcha/captcha-check";//
            string result = GetValidhtmlByPost(url, "answer=" + answer + "&login_site=E&rand=sjrand");

            context.Response.Write(result);
            context.Response.End();
            #endregion
        }

登陸

登陸需要post參數(username,password,appid)

 void Login(HttpContext context)
        {
            #region 登錄
            string username = "";
            if (!string.IsNullOrEmpty(context.Request["username"]))
                username = context.Request["username"];

            string password = "";
            if (!string.IsNullOrEmpty(context.Request["password"]))
                password = context.Request["password"];

            string url = "https://kyfw.12306.cn/passport/web/login";
            string result = GetValidhtmlByPost(url, "username=" + username + "&password="+ password + "&appid=otn");

            context.Response.Write(result);
            context.Response.End();
            #endregion
        }

HttpWebRequest 模擬get請求:
因爲12306是Https,所以有安全證書,和一般http請求有一些小的區別。

        //回調驗證證書問題
        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            // 總是接受    
            return true;
        }
 /// <summary>
        /// get請求(有證書驗證)
        /// </summary>
        /// <param name="Url">URL</param>
        /// <returns></returns>
        private string GetValidhtmlByGet(string Url)
        {
            HttpWebRequest webRequest;
            HttpWebResponse webResponse;
            try
            {
                //這一句一定要寫在創建連接的前面。使用回調的方法進行證書驗證。
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
                ServicePointManager.CheckCertificateRevocationList = true;

                webRequest = (HttpWebRequest)WebRequest.Create(Url);
                webRequest.Method = "GET";
                webRequest.Accept = "*/*";

                // 獲取對應HTTP請求的響應
                webResponse = (HttpWebResponse)webRequest.GetResponse();
                // 獲取響應流
                Stream responseStream = webResponse.GetResponseStream();
                // 對接響應流(以"utf-8"字符集)
                StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
                string result = reader.ReadToEnd();
                reader.Close();
                return result;

            }
            catch (Exception ex)
            {
                return "";
            }


        }

    /// <summary>
        /// 獲取文件流
        /// </summary>
        /// <param name="Url"></param>
        /// <returns></returns>
        private Stream GetStreamByGet(string Url)
        {
            HttpWebRequest webRequest;
            HttpWebResponse webResponse;
            cookie = new CookieContainer();
            try
            {
                //這一句一定要寫在創建連接的前面。使用回調的方法進行證書驗證。
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
                ServicePointManager.CheckCertificateRevocationList = true;

                webRequest = (HttpWebRequest)WebRequest.Create(Url);
                webRequest.Method = "GET";
                webRequest.Accept = "*/*";
                webRequest.CookieContainer = cookie;
                // 獲取對應HTTP請求的響應
                webResponse = (HttpWebResponse)webRequest.GetResponse();

                // 獲取響應流
                Stream responseStream = webResponse.GetResponseStream();
                return responseStream;


            }
            catch (Exception ex)
            {
                return null;
            }


        }

 ///<summary>
        ///post請求(有證書驗證)
        ///</summary>
        ///<param name="URL">url地址</param>
        ///<param name="strPostdata">發送的數據</param>
        ///<returns></returns>
        public string GetValidhtmlByPost(string url, string strPostData)
        {
            HttpWebRequest webRequest;
            HttpWebResponse webResponse;
            try
            {
                // 這一句一定要寫在創建連接的前面。使用回調的方法進行證書驗證。
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
                ServicePointManager.CheckCertificateRevocationList = true;

                webRequest = (HttpWebRequest)HttpWebRequest.Create(url);

                webRequest.Method = "POST";
                webRequest.ContentType = "application/x-www-form-urlencoded";
                webRequest.KeepAlive = true;
                webRequest.CookieContainer = cookie;


                byte[] buffer = Encoding.UTF8.GetBytes(strPostData);
                webRequest.ContentLength = buffer.Length;
                webRequest.GetRequestStream().Write(buffer, 0, buffer.Length);

                webResponse = (HttpWebResponse)webRequest.GetResponse();
                StreamReader reader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8);
                string result = reader.ReadToEnd();
                return result;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

Demo地址

http://download.csdn.net/download/qq237183141/10024750

關於

  1. 技術層面就是HTTPWebRequest、HttpWebResponse,這兩個類。
  2. 主要是12306業務的邏輯,例如查詢火車的json數據很亂,本人也是一個一個對着12306的頁面,才一一找到的業務的含義。
  3. 希望大家還是買票還是去12306上買,本文只爲學習上使用。歡迎大家一起學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章