欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

12306 余票查询API浅探索

程序员文章站 2024-03-17 21:56:04
...

余票查询请求分析

12306 余票查询API浅探索
点击查询,F12进入控制台,进入NetWork面板,查看发送的请求:
12306 余票查询API浅探索
点入请求查看详情,很明显,查询请求是第二条:
12306 余票查询API浅探索
查看请求Response:
12306 余票查询API浅探索
的确拿到了数据,不过好像有什么不对:
12306 余票查询API浅探索
数据好像做了什么处理,看不懂哦。想来应该是用JS解密的,OK,JS调试走起。

响应数据解密代码查找调试

回到NetWork面板,鼠标移到请求URL上,查看请求发起程序:
12306 余票查询API浅探索
点进去,直接定位到调用程序,设置断点:
12306 余票查询API浅探索
重新点击查询,开始逐步调试,调试过程要注意跟踪变量,最终会来到这一段程序:
12306 余票查询API浅探索
很显然,function cr(cQ, cS)就是执行将响应数据进行解密的程序,其中cQ,cS参数分别是:
对应加密数据集合:
12306 余票查询API浅探索
始发车站和终点车站字典:
12306 余票查询API浅探索
程序源代码如下:

    function cr(cQ, cS) {
        var cP = [];
        for (var cO = 0; cO < cQ.length; cO++) {
            var cT = [];
            var cN = cQ[cO].split("|");
            cT.secretStr = cN[0];
            cT.buttonTextInfo = cN[1];
            var cR = [];
            cR.train_no = cN[2];
            cR.station_train_code = cN[3];
            cR.start_station_telecode = cN[4];
            cR.end_station_telecode = cN[5];
            cR.from_station_telecode = cN[6];
            cR.to_station_telecode = cN[7];
            cR.start_time = cN[8];
            cR.arrive_time = cN[9];
            cR.lishi = cN[10];
            cR.canWebBuy = cN[11];
            cR.yp_info = cN[12];
            cR.start_train_date = cN[13];
            cR.train_seat_feature = cN[14];
            cR.location_code = cN[15];
            cR.from_station_no = cN[16];
            cR.to_station_no = cN[17];
            cR.is_support_card = cN[18];
            cR.controlled_train_flag = cN[19];
            cR.gg_num = cN[20] ? cN[20] : "--";
            cR.gr_num = cN[21] ? cN[21] : "--";
            cR.qt_num = cN[22] ? cN[22] : "--";
            cR.rw_num = cN[23] ? cN[23] : "--";
            cR.rz_num = cN[24] ? cN[24] : "--";
            cR.tz_num = cN[25] ? cN[25] : "--";
            cR.wz_num = cN[26] ? cN[26] : "--";
            cR.yb_num = cN[27] ? cN[27] : "--";
            cR.yw_num = cN[28] ? cN[28] : "--";
            cR.yz_num = cN[29] ? cN[29] : "--";
            cR.ze_num = cN[30] ? cN[30] : "--";
            cR.zy_num = cN[31] ? cN[31] : "--";
            cR.swz_num = cN[32] ? cN[32] : "--";
            cR.srrb_num = cN[33] ? cN[33] : "--";
            cR.yp_ex = cN[34];
            cR.seat_types = cN[35];
            cR.exchange_train_flag = cN[36];
            cR.houbu_train_flag = cN[37];
            cR.houbu_seat_limit = cN[38];
            cR.from_station_name = cS[cN[6]];
            cR.to_station_name = cS[cN[7]];
            cT.queryLeftNewDTO = cR;
            cP.push(cT)
        }
        return cP
    }

这段代码将用"|"连接的字符串数据进行分割,然后提取出段数据按照规则拼成新的JSON格式的数据,只是代码经过编译,不太好读。
12306 余票查询API浅探索

数据说明

经过解密的数据最终是这个样子的:

{
    "buttonTextInfo": "预订",
    "queryLeftNewDTO": {
        "arrive_time": "22:28",
        "canWebBuy": "Y",
        "controlled_train_flag": "0",
        "end_station_telecode": "BXP",
        "exchange_train_flag": "1",
        "from_station_name": "广州南",
        "from_station_no": "01",
        "from_station_telecode": "IZQ",
        "gg_num": "--",
        "gr_num": "--",
        "houbu_seat_limit": "",
        "houbu_train_flag": "0",
        "is_support_card": "1",
        "lishi": "09:38",
        "location_code": "Q7",
        "qt_num": "--",
        "rw_num": "--",
        "rz_num": "--",
        "seat_types": "OM9",
        "srrb_num": "--",
        "start_station_telecode": "IZQ",
        "start_time": "12:50",
        "start_train_date": "20191222",
        "station_train_code": "G70",
        "swz_num": "3",
        "to_station_name": "北京西",
        "to_station_no": "16",
        "to_station_telecode": "BXP",
        "train_no": "6c00000G700E",
        "train_seat_feature": "3",
        "tz_num": "--",
        "wz_num": "--",
        "yb_num": "--",
        "yp_ex": "O0M090",
        "yp_info": "GUrhKYs66fa4Qkmv0jeRFrWl6He53Xjen59rMW556V4Bo2s7",
        "yw_num": "--",
        "yz_num": "--",
        "ze_num": "有",
        "zy_num": "10"
    },
    "secretStr": "wQABjQbR9E%2Fn6hMLNSUP6p6v6djwCvahYS2xqJZ7ZB5mKfmzHhzudmjZD9TZm66N%2FpURPPvcFZS1%0A%2FO6bVpeIcPuevb3Xsf4x%2FJTLu6CUi4SonvPoO7TUT8ip85ZmS1mELs3nIIka%2Fx4wp%2FyNIcw%2FFj1F%0Ae2VPTbVjzxUl2i%2B5QffvnWvjjTVe39PXgJGzZVJzMU8tzTdzTkhr5ZFG%2BxfQ9X3PeEyPVE79hk46%0Amesr%2FmsV6M8AiH%2FTKPtxIYUiV9K7DwUlTPZP%2F%2FnV8TKjO7wiS0QQ95NQv9XyKqcw58OJ7UnAn0iH%0A"
}

这里面大多字段都是代码以及缩写,不过还是可以判断出一些有用字段:

{
    "buttonTextInfo": "预订",    => 按钮文字
    "queryLeftNewDTO": {         => 主要数据结构   
        "arrive_time": "22:28",  => 列车到达时间
        "canWebBuy": "Y",        => 是否支持网上购票
        "controlled_train_flag": "0",  => 
        "end_station_telecode": "BXP", =>
        "exchange_train_flag": "1",    =>
        "from_station_name": "广州南", => 列车始发站
        "from_station_no": "01",      
        "from_station_telecode": "IZQ",
        "gg_num": "--",   
        "gr_num": "--",  
        "houbu_seat_limit": "", => 候补车票余量
        "houbu_train_flag": "0", => 是否支持候补
        "is_support_card": "1", 
        "lishi": "09:38",   => 历时(列车运行时间)
        "location_code": "Q7",
        "qt_num": "--",
        "rw_num": "--",
        "rz_num": "--",
        "seat_types": "OM9",
        "srrb_num": "--",
        "start_station_telecode": "IZQ",
        "start_time": "12:50", => 发车时间
        "start_train_date": "20191222", => 发车日期
        "station_train_code": "G70", => 列车编号
        "swz_num": "3",
        "to_station_name": "北京西", => 终点站
        "to_station_no": "16",
        "to_station_telecode": "BXP",
        "train_no": "6c00000G700E", => 列车识别号
        "train_seat_feature": "3",
        "tz_num": "--",
        "wz_num": "--",
        "yb_num": "--",
        "yp_ex": "O0M090",
        "yp_info": "GUrhKYs66fa4Qkmv0jeRFrWl6He53Xjen59rMW556V4Bo2s7",
        "yw_num": "--", => 硬卧
        "yz_num": "--", => 硬座
        "ze_num": "有", 
        "zy_num": "10" 
    },
    "secretStr": => 加密字符串  "wQABjQbR9E%2Fn6hMLNSUP6p6v6djwCvahYS2xqJZ7ZB5mKfmzHhzudmjZD9TZm66N%2FpURPPvcFZS1%0A%2FO6bVpeIcPuevb3Xsf4x%2FJTLu6CUi4SonvPoO7TUT8ip85ZmS1mELs3nIIka%2Fx4wp%2FyNIcw%2FFj1F%0Ae2VPTbVjzxUl2i%2B5QffvnWvjjTVe39PXgJGzZVJzMU8tzTdzTkhr5ZFG%2BxfQ9X3PeEyPVE79hk46%0Amesr%2FmsV6M8AiH%2FTKPtxIYUiV9K7DwUlTPZP%2F%2FnV8TKjO7wiS0QQ95NQv9XyKqcw58OJ7UnAn0iH%0A"
}

其他字段,大家可以自己对比界面进行推测,最后的secretStr加密字符串目前不知道是什么,不过感觉像是查询列车详情需要的密匙。不过,拥有这些信息已经足够用Python写一个自己的余票查询小程序了。有没有什么想法. . . . . .
12306 余票查询API浅探索