12306 抢票脚本 基于laravel console
12306 抢票脚本 基于laravel console
主要接口
- POST https://kyfw.12306.cn/otn/login/checkUser 验证用户是否登录
- GET https://kyfw.12306.cn/otn/login/init 登录页面初始化
- GET https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.123456789 获取验证码图像接口 末尾是随机数
- POST https://kyfw.12306.cn/passport/captcha/captcha-check 验证码验证
- POST https://kyfw.12306.cn/passport/web/login 登录请求
- POST https://kyfw.12306.cn/passport/web/auth/uamtk 获取uamtk 我也不知道是什么玩意
- POST https://kyfw.12306.cn/otn/uamauthclient 最后登录成功
- POST https://kyfw.12306.cn/otn/passengers/init 获取乘车人 其实乘车人可以在请求
提交订单
接口时通过html 正则匹配可以获取,作为抢票工具来说,当然先确定好,后面就只顾抢票就行了。 - GET https://kyfw.12306.cn/otn/leftTicket/query 车次查询
- POST https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest 请求
提交订单
- POST https://kyfw.12306.cn/otn/confirmPassenger/initDc 请求订单初始化
- POST https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo 请求
验证订单信息
- POSThttps://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue 确认
订单信息
注意事项
在调用12306接口时,最好把每次请求所返回的cookie
都保存下来,以便下次调用其他接口是顺带上。PHP 建议保存全局array
、 Java 建议保存一个Map
做好每当有新值时做好新增和替换。在请求每一个接口时 要判断body是否未空字符串,很多时候请求返回为空需要重复请求直到有正确返回。
接口描述
- 验证用户是否登录
请求:
请求参数 | 请求值 |
---|---|
_json_att | 空字符 |
返回:
1
2
3
4
5
6
7
8
9
10
11
{
"validateMessagesShowId": "_validatorMessage",
"status": true,
"httpstatus": 200,
"data": {
"flag": false
},
"messages": [],
"validateMessages": {}
}
- 登录页面初始化
这个没什么好说的相当于打开一个页面 记得保存cookie
- 获取验证码图像接口
body 返回图像的二进制流,注意: 头部有Set Cookie : _passport_session=abc;_passport_ct=abc
建议将body的内容md5做一个验证码库,以后脚本就可以根据验证码库实现自动登录 - 验证码验证
请求:
请求参数 | 请求值 |
---|---|
answer | 图片答案坐标值 |
login_site | E |
rand | sjrand |
当验证码验证失败时,请在全局cookie 中删除两个KEY _passport_session,_passport_session
,这样才能保证下次获取的验证码图像是有效的
返回:
1
2
{"result_message":"验证码校验成功","result_code":"4"}
- 登录请求
请求:
请求参数 | 请求值 |
---|---|
username | 用户名 |
password | 密码 |
appid | otn |
返回:
1
2
{"result_message":"登录成功","result_code":0,"uamtk":"hNFI2iowH46SkgEOdsC1jPSm5MeM50S1wVknuZWOCs4511110"}
- 获取uamtk
请求:
将上面返回的uamtk设置到全局Cookie
中 Set Cookie: uamtk=hNFI2iowH46SkgEOdsC1jPSm5MeM50S1wVknuZWOCs4511110
请求参数 | 请求值 |
---|---|
appid | otn |
返回:
1
2
{"result_message":"验证通过","result_code":0,"apptk":null,"newapptk":"1D2_g7EUpnq2hGh6OCxABPYzIkRHuXEHjaLQCIoWh5Erw1110"}
- 请求最后登录成功
请求:
请求参数 | 请求值 |
---|---|
tk | 1D2_g7EUpnq2hGh6OCxABPYzIkRHuXEHjaLQCIoWh5Erw1110 |
返回:
1
2
{"apptk":"1D2_g7EUpnq2hGh6OCxABPYzIkRHuXEHjaLQCIoWh5Erw1110","result_code":0,"result_message":"验证通过","username":"某某某"}
- 获取乘车人
请求:
请求参数 | 请求值 |
---|---|
_json_att | 空字符 |
返回 html:
1
2
3
4
5
6
7
//正则匹配出乘车人信息
preg_match('/passengers=\[.*\];/', $body, $mth);
$passengerObj = str_replace("passengers=", '', $mth[0]);
$passengerObj = str_replace(";", '', $passengerObj);
$passengerJsonStr = str_replace("'", '"', $passengerObj);
$passengerJson = json_decode($passengerJsonStr, true);
- 车次查询
请求:
请求参数 | 请求值 |
---|---|
leftTicketDTO.train_date | 乘车日期2018-01-01 格式 |
leftTicketDTO.from_station | 从哪去 对应车站代码 |
leftTicketDTO.to_station | 到哪里 对应车站代码 |
purpose_codes | ADULT |
返回:
1
2
3
4
5
6
{"data":
{"flag":"1",
"map":{"BJQ":"深圳东","OSQ":"深圳西","SZQ":"深圳","UNG":"龙南"},
"result":[
"%2Fomy92SddEWJNSkeEqDWLNcqHjN%2F2yds3mb6w6oK4txUa51Av3QrpNUfdUhkrG%2Fk1Y%2FMMfL2X6ap%0AjTJH%2B2cjxLktehVEtsDOBc7F9bdCS1KUzb8Yhasipp1svkaosOo147jsFB9sXwLPl1WmgmzZs7hk%0AfpBRxtnhXzXHvih6H9sN%2Fn5I7%2FJN8blPFpiBXWzMKDPUzQqb4kfBNHlGh%2B%2FVAuwu8pTs85C4oXZ2%0AXGrtpRpO0wNWoHbb5BxmwOs9WEpxyKekxw%3D%3D|预订|240000G1010D|G101|VNP|AOH|VNP|AOH|06:43|12:39|05:56|Y|zRcaqkbreGzvNhhf2Y15yLdPELNQWpW%2FtDFmtCg8bPhFRRSn|20180210|3|P2|01|11|1|0|||||||||||有|有|2||O0M090|OM9|0"]},"httpstatus":200,"messages":"","status":true}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//result 结果送上 通过 `|` 分隔字符串
[
'cc' => $d[3], //车次
'cf' => $d[8], //出发时间
'dd' => $d[9], //到达时间
'ls' => $d[10], //历时
'swz' => $d[32], //商务座/特等座 ok
'ydz' => $d[31], //一等座 ok
'edz' => $d[30], //二等座 ok
'gjrw' => $d[21], //高级软卧 21
'rw' => $d[23], //软卧 ok
'dw' => $d[33], //动卧 ok
'yw' => $d[28], //硬卧 ok
'rz' => $d[24], //软座 ok
'yz' => $d[29], //硬座 ok
'wz' => $d[26], //无座 ok
'qt' => $d[22], //其他 ok
'secretStr' => urldecode($d[0])
]
- 请求提交订单
请求:
请求参数 | 请求值 |
---|---|
secretStr | 上面php的secretStr |
train_date | 去程日期 |
back_train_date | 反程日期 |
tour_flag | dc 单程 wc 往返 |
purpose_codes | ADULT |
query_from_station_name | 始发站名称 |
query_to_station_name | 到达站名称 |
undefined | 空字符串 |
返回:
1
2
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":"N","messages":[],"validateMessages":{}}
- 请求订单初始化
请求:
请求参数 | 请求值 |
---|---|
_json_att | 空字符串 |
返回html:
1
2
3
4
5
6
7
8
9
10
11
12
13
//正则匹配需要的值: globalRepeatSubmitToken,ticketInfoForPassengerForm
preg_match("/globalRepeatSubmitToken\h=\h\'.*\'\;/", $body, $ma);
$st = str_replace("globalRepeatSubmitToken = '", '', $ma[0]);
$repeatSubmitToken = str_replace("';", '', $st);
preg_match("/ticketInfoForPassengerForm=.*\}\;/", $body, $ma2);
//是个json
$st1 = str_replace("ticketInfoForPassengerForm=", '', $ma2[0]);
$st2 = str_replace(";", '', $st1);
$ticketInfoForPassengerForm = str_replace("'", '"', $st2);
$ticketInfoForPassengerForm = json_decode($ticketInfoForPassengerForm, true);
- 验证订单信息
请求:
请求参数 | 请求值 |
---|---|
cancel_flag | 2 |
bed_level_order_num | 000000000000000000000000000000 |
passengerTicketStr | 座位类型,0,车票类型,姓名,身份正号,电话,N(多个的话,以逗号分隔) |
oldPassengerStr | 姓名,证件类别,证件号码,用户类型 |
tour_flag | dc 单程 wc 往返 |
randCode | 空字符串 |
whatsSelect | 1 |
_json_att | 空字符串 |
REPEAT_SUBMIT_TOKEN | 上面php repeatSubmitToken |
返回:
1
2
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"ifShowPassCode":"N","canChooseBeds":"N","canChooseSeats":"Y","choose_Seats":"OM","isCanChooseMid":"N","ifShowPassCodeTime":"731","submitStatus":true,"smokeStr":""},"messages":[],"validateMessages":{}}
- 确认订单信息
请求:
请求参数 | 请求值 |
---|---|
passengerTicketStr | 同上 |
oldPassengerStr | 同上 |
randCode | 空字符串 |
purpose_codes | 00 |
key_check_isChange | 上面 php $ticketInfoForPassengerForm[‘key_check_isChange’] |
leftTicketStr | 上面 php $ticketInfoForPassengerForm[‘leftTicketStr’] |
train_location | 上面 php $ticketInfoForPassengerForm[‘train_location’] |
choose_seats | 空字符串 |
seatDetailType | 000 |
whatsSelect | 1 |
roomType | 00 |
dwAll | N |
_json_att | 空字符串 |
返回:
1
2
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"submitStatus":true},"messages":[],"validateMessages":{}}
其他
本文由作者按照 CC BY 4.0 进行授权