1.获取指定车次的余票信息
-
查询余票是整个自动化流程中非常重要的环节
-
查询余票的地址是https://kyfw.12306.cn/otn/leftTicket/init
-
为了减轻12306系统的负担,忙时查票需要先登陆帐户.
首先请求12306的查询余票的界面https://kyfw.12306.cn/otn/leftTicket/init
,请求之前,先按F12
,切换到network选项卡,查看请求的会话连接.
-
其实在请求这个界面的时候,发出了一个交互https://ad.12306.cn/sdk/webservice/rest/appService/getAdAppInfo.json?placementNo=0004&clientType=2&billMaterialsId=ac3398e4e6b7417789051de0894b4516
,获得的响应中,带有一组cookie.
-
参数格式:Cookie:fp_ver=4.5.1; RAIL_EXPIRATION=1505841771820; RAIL_DEVICEID=lRJS4LUFlzx7hr4FQRpeJJpsadV-NKiN74dplfA37atNLMDEbaQ5C6J7rs1hRym9o8t_LtIR_0jv0kqT7Os6tHJkRPeq_rm5Xk9445hd7HyNMxnS-2CHmLBB9Mjid_JCYsuaYzPK-oM8CWUUNG5Ebdrg3bvyX9ez
-
这组参数对后期提交订单,有很关键的作用,这里先铺个垫.

按照正常查询余票的方法,选择好出发地,目的地,日期后,(以9.19,长沙-南宁为例子)查询,会发出2个请求,其中包含了余票信息的请求才是我们需要的.
https://kyfw.12306.cn/otn/leftTicket/queryX?leftTicketDTO.train_date=2017-09-19&leftTicketDTO.from_station=CSQ&leftTicketDTO.to_station=NNZ&purpose_codes=ADULT
-
这个返还的响应包含了余票信息的json,以及做一部操作需要用到的cookie

在请求的报文中,有一个6个键值对的json格式的报文.

json格式如下:
-
展开data的话,下面还带有3个键值对,分别是map,flag,result
-
map注释记录了查询的始发和到达,以及真正停靠的实际车站名称
-
而result,则是一个以列表为值的数组,每一条记录,记载了主要的的车次信息.
{
"validateMessagesShowId":"_validatorMessage",
"status":true,
"httpstatus":200,
"data":{
"result":Array[17],
"flag":"1",
"map":{
"NFZ":"南宁东",
"CWQ":"长沙南",
"CSQ":"长沙",
"NNZ":"南宁"
}
},
"messages":[
],
"validateMessages":{
}
}
继续展开result,发现其实,每一个列表里面的额成员,都是以|进行分割,一共有35个,说明可以展示35个字段信息
"result":[
"|23:00-06:00系统维护时间|38000K16270A|K1627|ZZF|NNZ|CSQ|NNZ|04:42|19:08|14:26|IS_TIME_NOT_BUY|GxZzagLz9ugMJpCswv%2FPEZaZNl%2BDiFVaouh6Nb0zNTm%2FbesL5RbzwxxrtC0%3D|20170918|3|F1|10|20|0|0||||13|||有||有|有|||||10401030|1413",
......此处省略很多条记录........
"|23:00-06:00系统维护时间|62000K177901|K1779|CSQ|NNZ|CSQ|NNZ|21:04|11:38|14:34|IS_TIME_NOT_BUY|JEsmMbhy8nZeDW56jALAIE%2FHkKy7o99ZLSD9SAbbFxDdTNOaxKqg3QTO63Y%3D|20170919|3|Q7|01|10|0|0||||9|||有||有|有|||||10401030|1413"
],
进一步对记录进行解析,会得到如下信息:
-
比较重要的是0对应的参数,应该是这趟车的一组钥匙.
-
1代表可以预定,3车次,8,9,10代表出发时间,到达时间,历时,12代表一组校验参数,13则是日期
-
座次方面,23代表软卧,25特等座,26无座,29硬座
-
座位有三种状态:余票的数字,有,无
0 rfPu9cd9%2FCO4fTYKlDg0pHTTRVqg6QsSgCaFh3LqjsT8iktXc3FDpW71HgrlaFjD10wL%2BijItcmG%0AIKYBLbbOC6y%2FI7ULR39mb8S1p9gWnYgDsIesosW2kfKac0sEiin8jXnC3BY1Vqu0jgaQ5Nikje6s%0Azl4YtA%2FIfbyC2RWn3eEYU%2BP4BfHZWmSypXkyOOvYKV2OcJZ1yNeysVi4ZcDJTStYniRBlwpP%2BjJ8%0AjBXQgTztdr0Y
1 预订
2 5l000G150500
3 G1505 (车次)
4 NKH
5 NFZ
6 CWQ
7 NFZ
8 14:06 (出发时间)
9 19:51 (到达时间)
10 05:45 (历时)
11 Y
12 QLDC3b1%2FMGi7CRnV4Aoh5SW%2Bu92aGXTN%2BMXppgw5dC2G1uXn
13 20170919
14 3
15 H2
16 18
17 25
18 0
19 0
20
21
22
23 (软卧)
24
25 (特等座)
26 (无座)
27
28
29 (硬座)
30 有 (二等座)
31 无 (一等座)
32 无
33
34 O0M090
35 OM9
2.模拟查询余票

事实上,它是一个以@
开头的文件,中间用|
进行分割的长字符串.
@bjb|北京北|VAP|beijingbei|bjb|0@bjd|北京东|BOP|beijingdong|bjd|1@bji|北京|BJP|beijing|bj|2...
@bjb|北京北|VAP|beijingbei|bjb|0
@bjd|北京东|BOP|beijingdong|bjd|1
@bji|北京|BJP|beijing|bj|2
因为,这个字符串过长,所以处理的方法是,将它保存到一个文件station_names.py
中,做成
station_names ='@bjb|北京北|VAP|beijingbei|bjb|0@bjd|北京东|BOP|beijingdong|bjd|1@bji|北京|BJP|beijing|bj|2
赋值给变量station_names的形式,通过导入这个变量,引用它,否则显示的字符太多,会拖垮编辑器.
-
实际的处理中,是把这个字符串变成一个city的字典{‘中文站名’:’站名编码’},通过city[‘长沙’]的方式获取对应的值CSQ,具体实现方式如下
from station_names import station_names
for i in station_names.split('@'):
if not i:
continue
tmp_list=i.split('|')
city[tmp_list[1]]=tmp_list[2]
from_station=city['长沙']
to_station=city['南宁']
3.监控需要的车次余票信息
通常我们要做的事情,不是去监控有的车票,而是去监控没有的车票,如果有票了,提醒我们去下单购买,所以需要弄清楚的事情是:
-
需要什么车次,有没有票
-
需要什么座次的票(一等座,卧铺,还是硬座)
from __future__ import unicode_literals
import urllib,urllib2,ssl,cookielib,json,damatuWeb,time
from station_names import station_names
c=cookielib.LWPCookieJar()
cookie=urllib2.HTTPCookieProcessor(c)
opener=urllib2.build_opener(cookie)
urllib2.install_opener(opener)
ssl._create_default_https_context=ssl._create_unverified_context
city={}
station_names=station_names.decode('utf-8')
for i in station_names.split('@'):
if not i:
continue
tmp_list=i.split('|')
city[tmp_list[1]]=tmp_list[2]
from_station=city[raw_input("请输入出发站名:").decode('utf-8')]
to_station=city[raw_input("请输入到达站名:").decode('utf-8')]
train_date=raw_input("请选择日期(2017-09-20):")
def getTrain():
url='https://kyfw.12306.cn/otn/leftTicket/queryX?leftTicketDTO.train_date=%s&leftTicketDTO.from_station=%s&leftTicketDTO.to_station=%s&purpose_codes=ADULT'%(train_date,from_station,to_station)
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36',
'Referer':'https://kyfw.12306.cn/otn/leftTicket/init',
'cookie':'JSESSIONID=AA5E16A1DF7B051EAB5055BA2B95537D; route=c5c62a339e7744272a54643b3be5bf64; BIGipServerotn=435159562.24610.0000; BIGipServerpool_passport=317522442.50215.0000; fp_ver=4.5.1; RAIL_EXPIRATION=1505841771820; RAIL_DEVICEID=lRJS4LUFlzx7hr4FQRpeJJpsadV-NKiN74dplfA37atNLMDEbaQ5C6J7rs1hRym9o8t_LtIR_0jv0kqT7Os6tHJkRPeq_rm5Xk9445hd7HyNMxnS-2CHmLBB9Mjid_JCYsuaYzPK-oM8CWUUNG5Ebdrg3bvyX9ez; _jc_save_fromStation=%u957F%u6C99%2CCSQ; _jc_save_toStation=%u5357%u5B81%2CNNZ; _jc_save_fromDate=2017-09-19; _jc_save_toDate=2017-09-17; _jc_save_wfdc_flag=dc',
}
req=urllib2.Request(url,headers=headers)
h=opener.open(req).read().decode('utf-8')
h=json.loads(h)
return h['data']['result']
html=getTrain()
for i in html:
tmp_list=i.split('|')
if tmp_list[30]=='有' and tmp_list[30] !='':
print tmp_list[13],tmp_list[3],tmp_list[8],tmp_list[9],tmp_list[10],'有票',tmp_list[0]
达到了预期的效果…

总结
理解12306的余票查询信息,是实现自动化抢票的前提.这节重点剖析了12306查询余票后返回的信息的机构,请求这些参数从哪里获取,如果模拟一个请求去查询所需要的票信息.每个记录信息对应的字段又是什么含义.熟悉掌握后,才能再下一步自动下单,做好准备工作,所以请重点学习.
未经允许不得转载:http://www.yueguangzu.net
逗逗网 »
[12306专题]第四篇12306的余票查询
最新评论