12306改版以后简单抢票软件的实现(二)完结

    上一篇文章讲完了12306网站模拟登录的部分,看这里 12306改版以后简单抢票软件的实现html

    如今把后面的步骤所有分析一下。正则表达式

本文做者 http://www.cnblogs.com/russellwang,转载请标明出处

    登陆完成要选择买票人的信息,那么怎么得到帐户中经常使用联系人的信息呢?访问这个地址:https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOsjson

访问这个页面须要两个参数(@code_flyer提醒这里可能不须要参数,暂时没验证),
cookie

    说一下第二个参数,REPEAT_SUBMIT_TOKEN是从提交订单后选择乘客信息的页面中得到的,这个页面在后面还会用到,先给出地址:https://kyfw.12306.cn/otn/confirmPassenger/initDc,页面头部有一段js,找到globalRepeatSubmitToken对应的值就是须要的参数dom

 

    得到用户信息后能够在界面上展现出来,供用户选择,或者直接提供用户输入信息的地方,只须要姓名、身份证号、手机号就能够了,这里要求输入的买票人信息是帐号中已经认证过的人,12306作了实名认证了。网站

本文做者 http://www.cnblogs.com/russellwang,转载请标明出处

    准备步骤都完成了,下面应该就是查询余票了,查票的地址和参数以下:https://kyfw.12306.cn/otn/leftTicket/queryT?leftTicketDTO.train_date=2015-02-16&leftTicketDTO.from_station=SZH&leftTicketDTO.to_station=XCH&purpose_codes=ADULT编码

    参数分别表明出发日期,出发站,到达站,车票类型,复杂一点的就是出发站、到达站的代号问题了,这也难不倒咱们勤劳的猿类,查询页面 https://kyfw.12306.cn/otn/leftTicket/init 加载的时候引入了一个站点名称拼音和代号对应的js文件,spa

    访问这个地址:https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8241,密密麻麻的站点和代号啊,看得我眼花缭乱的,赶忙找到你在的城市吧!我先拿前三个数据来讲明一下数据的格式,插件

1 @bjb|北京北|VAP|beijingbei|bjb|0@bjd|北京东|BOP|beijingdong|bjd|1@bji|北京|BJP|beijing|bj|2

    每条记录以"@"开头,剩下的用"|"来分隔,全大写的代号就是咱们在查询余票时用到的出发站、到达站编号,一开始就把这些信息保存起来,查询时直接使用是否是能够快那么一点点呢?code

    差一点忘记了,查询以前须要先设置cookie值,记录查询信息,须要设置的cookie字段以下图所示:

    其中JSESSIONID和BIGipServerotn在上篇文章登陆时已经得到了,剩下的几个字段就是你查询车票用到的信息,_jc_save_fromStationh和_jc_save_toStation将要查询站点的中文名和编号按照特定方式编码组成,中文名转为Unicode值并转为全大写,而后将"\"替换为"%",后面拼接站点对应编号便可。

    下面来看查询余票返回的结果,数据为json格式,为了方便展现,特地找了一个只有一辆列车的区间:昆明--徐州,其余区间返回的数据格式也是相似的。

{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":[{"queryLeftNewDTO":{"train_no":"800000K4920F","station_train_code":"K492","start_station_telecode":"KMM","start_station_name":"昆明","end_station_telecode":"JNK","end_station_name":"济南","from_station_telecode":"KMM","from_station_name":"昆明","to_station_telecode":"XCH","to_station_name":"徐州","start_time":"12:40","arrive_time":"02:59","day_difference":"2","train_class_name":"","lishi":"38:19","canWebBuy":"IS_TIME_NOT_BUY","lishiValue":"2299","yp_info":"1027853214407805000910278503273048850106","control_train_day":"20201231","start_train_date":"20150202","seat_feature":"W3431333","yp_ex":"10401030","train_seat_feature":"3","seat_types":"1413","location_code":"M1","from_station_no":"01","to_station_no":"27","control_day":59,"sale_time":"1430","is_support_card":"0","gg_num":"--","gr_num":"--","qt_num":"--","rw_num":"9","rz_num":"--","tz_num":"--","wz_num":"有","yb_num":"--","yw_num":"有","yz_num":"有","ze_num":"--","zy_num":"--","swz_num":"--"},"secretStr":"MjAxNS0wMi0wMiMwMCNHNzI5OCMwMjozMyMyMDoyMSM1NTAwMEc3Mjk4MDAjT0hII1VVSCMyMjo1NCPoi4%2Flt57ljJcj5b6Q5bee5LicIzAyIzA4I08wMjQ5MDAwNTlNMDQxOTAwMDUwTzAyNDkwMzAwMCNIMSMxNDE4OTk2MjQ0NjgxIzA5MEI3MkQ5NEFDQTgyQzI3MjM2MTc5RTE5ODA3RDQ2NkUxRDAxNjY2MDM1MzVFQzE0QTZFMUQ4","buttonTextInfo":"预订"}],"messages":[],"validateMessages":{}}

    慢慢解析这个数据,咱们可以看到车次 station_train_code:K492,座位信息:"gg_num":"--","gr_num":"--","qt_num":"--","rw_num":"9","rz_num":"--","tz_num":"--","wz_num":"有","yb_num":"--","yw_num":"有","yz_num":"有","ze_num":"--","zy_num":"--","swz_num":"--",这些信息包括了座位类型和剩余数量,遇到“有”或者数字的座位表明咱们能够预订的,其余的应该是没有这种类型的座位或无票。筛选车票的逻辑能够根据本身的须要进行定制了,能够预先定义好须要哪一个车次什么类型的座位,发现能预约的车票赶忙下手,到下一步去提交订单吧,若是没有合适的车票你能够在查询筛选一下,这就在不停的刷票了。这里还有一个secretStr是比较重要的,待会提交订单的时候要用到,因此先把这个值保存起来。

本文做者 http://www.cnblogs.com/russellwang,转载请标明出处

    下面的这段内容是在12306改版以后新添加进去的,原理和登陆时同样,增长了动态的参数名和值来判断在提交订单时是否是抢票插件的请求,仍是看余票查询页面https://kyfw.12306.cn/otn/leftTicket/init,新加载脚本的地方在这

    一样访问里面的内容,得到key的值并计算value值,计算方法参考上一票文章,12306改版以后简单抢票软件的实现。后面提交订单的时候能用到这个key跟value值。

    筛选完能预订的列车,12306网站还作了一个检验https://kyfw.12306.cn/otn/login/checkUser,验证你有没有登陆的,这个时候你要是没有登陆那就悲剧了,想一想先你刷了半天的票,忽然发现一张能购买的了,这时候告诉你“去登录”,跟这张票说byebye吧。前面咱们是先登陆而后查询余票的,因此检查是否登陆这一步是能够跳过去的,直接进入下一步,提交订单。

    提交订单的地址:https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest,这里的参数用到了前面保存的车票secretStr和计算的key、value值,参数见下图:

    这里须要根据返回的结果判断是否成功,成功以后12306网站会跳转到选择乘客、输入验证码的页面https://kyfw.12306.cn/otn/confirmPassenger/initDc,这个页面在前面得到经常使用联系人的地方用到过。在这里咱们从页面代码中从新获取一下globalRepeatSubmitToken的值,方法在文中开头处那一段,这个值在检查确认订单的时候用到,一样在这个页面得到key_check_isChange的值,用正则来匹配,对应的正则表达式为 'key_check_isChange':'(.*?)',本身验证一下,保存这个值后面使用。在程序中咱们须要将前面准备好的用户信息模拟提交一下,并查看返回的结果是否成功。具体来分析一下,首先要处理的仍是新增长的验证,同登陆步骤和上面的提交订单步骤,要先得到key和value值,这里就不在赘述。而后请求一个新的验证码,和登录以前的验证码地址是相同的,可是参数有所区别,

,注意这里的参数,将验证码ocr自动识别或手动输入以后最好先提交给12306后台验证一下,这一步能够跳过去直接到下一步检查确认订单,可是若是验证码错误的话也不能蒙混过关,检查订单时仍是会校验的。

    下面这一步是检查确认订单,请求地址是https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo,传入的参数比较多,下图所示

    分开来说这几个参数,cancel_flag,bed_level_order_num,tour_flag,_json_att 用图中固定值便可,randCode是上一步请求的验证码,NTkzODQy这一对值是验证是不是抢票助手用的key,value值,前面已得到,REPEAT_SUBMIT_TOKEN的值也在页面https://kyfw.12306.cn/otn/confirmPassenger/initDc中从新得到了,就剩下passengerTicketStr和oldPassengerStr这是根据乘客的用户信息拼接出来的,参考一段别人的代码(hncdyj)

 1 public static String getOldPassengerStr(List<UserInfo> userInfo) {  2     String oldStrs = "";  3     for (int i = 0; i < userInfo.size(); i++) {  4         String oldStr = userInfo.get(i).getName() + "," + userInfo.get(i).getCardType() + "," + userInfo.get(i).getCardID() + "," + userInfo.get(i).getType();  5         oldStrs += oldStr + "_";  6  }  7     return oldStrs;  8 }  9 public static String getPassengerTicketStr(List<UserInfo> userInfo) { 10     String oldStrs = ""; 11     for (int i = 0; i < userInfo.size(); i++) { 12         String oldStr = ""; 13         if ("WZ" == userInfo.get(i).getSeatType()) { 14         } else { 15             oldStr = userInfo.get(i).getSeatType(); 16  } 17         String bR = oldStr + ",0," + userInfo.get(i).getTickType() + "," + userInfo.get(i).getName() + "," + userInfo.get(i).getCardType() + "," + userInfo.get(i).getCardID() + ","
18         + (userInfo.get(i).getPhone() == null ? "" : userInfo.get(i).getPhone()) + ",N"; 19         oldStrs += bR + "_"; 20  } 21     return oldStrs.substring(0, oldStrs.length() - 1); 22 }

结果大概是这个样子的 

passengerTicketStr-->1(座位类型),0,1(车票类型),张三(乘客姓名),1(证件类型),320xxxxxx(身份证号),151xxxx(手机号),N
oldPassengerStr-->张三(乘客姓名),1(证件类型),320xxxxxx(身份证号),1_

能够本身买票时抓包验证,这里给出座位类型和代号的对应关系:商务座(9),特等座(P),一等座(M),二等座(O),高级软卧(6),软卧(4),硬卧(3),软座(2),硬座(1),无座(1)(修正为1,感谢@code_flyer的提醒),能够根据本身的须要预先设置要买的座位类型,根据查询结果判断对应的类型是否有票。

这一步提交成功根据返回的信息判断确认定可是否经过,常见的错有“非法请求”,“输入的验证码错误”等。

本文做者 http://www.cnblogs.com/russellwang,转载请标明出处

经过以后离成功就很近啦,来看一下排队人数的状况吧,地址:https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount,参数

    要查询的车次和leftTicket信息在查询余票时获得的信息里面有,不超过排队人数的状况下就进行下面一步吧

    确认单笔订单 https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue

  

    这些参数都比较简单了,前面都用到过了或者已经保存下来准备这里使用的,train_location在查询余票返回的结果里。

    后面还能够查询出票等待时间,https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime?random=1419117908672&tourFlag=dc&_json_att=&REPEAT_SUBMIT_TOKEN=xxxxxxxxxxxxxx,参数请作相应替换,random对应的应该是当前时间。

本文做者 http://www.cnblogs.com/russellwang,转载请标明出处

    最后还须要补充一点知识,12306返回的信息有些是gzip压缩格式的,能够根据返回信息头中的Content-Encoding来判断,读取这些返回的信息流时须要用到GZIPInputStream,不然获得的是一堆乱码。

    OK,到这里整个流程走完了,应该能买到你心仪的火车票了,也算是了却了一桩心事。

    买票的所有流程简单介绍了一下,可能不够清晰,可是有心人根据这些分析应该能作出一个简单的抢票软件了,若是你用本身作的抢票软件买到了票,请到这里来分享一下。在作的过程当中有什么疑问也欢迎到这里来提问,我会尽可能及时帮助解答,不必定全部的问题都能解决。

    空余的时间还作了一个抢小米的软件,如今抢火车票的文章告一段落了,闲下来的时候把抢小米的过程也分析一下。

    感谢你看到了这里!欢迎留言讨论,也但愿你帮我点一下“推荐” 

    

    博文做者:russellwang
    博文出处:http://www.cnblogs.com/russellwang
    本文版权归做者和博客园共有,欢迎转载,但须保留此段声明,并给出原文连接,谢谢合做!
相关文章
相关标签/搜索