Python实现12306购票(四)
该系列最后一篇文章,来实现提交订单(购票),不过:不支持付钱。
本文只涉及一个函数confirm_single_for_queue
,位于此文件
提交订单
在前面余票查询完成后,我们就可以真正地提交订单了,提交订单的请求如下:
POST https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue
参数:
passengerTicketStr | oldPassengerStr | randCode |
purpose_codes | key_check_isChange | leftTicketStr |
train_location | choose_seats | seatDetailType |
is_jy | is_cj | whatsSelect |
roomType | dwAll | _json_att |
REPEAT_SUBMIT_TOKEN | encryptedData |
前面几个参数(从randCode
到train_location
)都与前一篇文章一样,来自于ticketInfoForPassengerForm
这个变量,REPEAT_SUBMIT_TOKEN
与前面一样来自网页的JS变量:globalRepeatSubmitToken
。另外有几个可以写死的参数:seatDetailType="000"
、is_jy="N"
、is_cj="N"
、whatsSelect="1"
、roomType="00"
、dwAll="N"
、_json_att=""
。
这样一来,需要解决的只剩两个参数了:choose_seats
、encryptedData
选座功能
choose_seats
顾名思义是选座,JS代码如下:
function j() {
var x = "";
$.each($("div#id-seat-sel div.seat-sel-bd a"), function() {
if ($(this).hasClass("cur")) {
var y = $(this).attr("id");
x += y
}
});
return x
}
简单分析一下代码,就是把选到的座位的id直接加起来。两个订单的选座界面长这样(若有n个订单则会有n排座位):
找到其中一个座位的html代码如下:
根据这个id与前面的JS逻辑,就可以直接写出选座的逻辑了。举个例子,如果我选了第一排的A和第二排的B,那么choose_seats
即是1A2B
。
(没用的)加密数据
解决了choose_seats
,还剩最后一个最复杂的参数encryptedData
。
经过追踪,它来自于window.json_ua.toString()
这个函数,它会产生一个比较随机的字符串,而这个函数来自于一个近三万行的JS文件,该文件经过了压扁控制流混淆,通过大量的switch case
语句将源代码打散,分析难度很大,我直接裂开。
但后来我发现压根就不需要提交这个变量…那就不用研究了,真是喜大普奔。
流程总结
到此为止,12306的购票流程已经全部走了一遍,总结一下就是:
- 登录(建议扫二维码)
- 查票(
https://kyfw.12306.cn/otn/leftTicket/query
,该链接动态变化) - 选票(
https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest
)添加1个或多个订单 - 余票查询(
https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo、https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount
) - 提交订单(
https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue
)
但毕竟12306平台异常复杂,代码中肯定会有不少处理不妥的地方,比如某些重要的参数被我偷懒直接写死了,但实际上可能会发生变化。若各位大佬有这方面的经验,希望能指出。