实现原理比较简单,就是调用 12306 的查票接口获取 JSON 数据再重新组装,取出合适的数据。配合发送邮件模块,就能实现实时获取余票数据。
由于发现 12306 经常进行查票接口部分参数的更换,下面就以谷歌浏览器为例寻找一个查票接口:
如图,在谷歌浏览器的调试窗口 network 标签页下点击网页上的查询按钮可以看到一个 get 请求,其请求的数据就是我们需要的 JSON 数据。
看一下原生数据,在浏览器中打开这个链接:
可以看出需要我们传递三个参数:
查询日期,如:2018-10-17
出发地火车站电报码,如:BJP (北京)
到达地火车站电报码,如:KMM (昆明)
不知道电报码的话百度一下就 ok 了。
好,现在就处理数据,看代码:
我们需要循环遍历每辆车的信息,原始数据 result 中每一条就是一个车次信息,其间采用竖线分隔。
使用 python 取子串获取的信息如下:
item = {}
# 循环遍历每辆列车的信息
data_list = raw_train.split('|')
train_type = data_list[3][0]
print data_list
# 车次号码
item['train_no'] = data_list[3]
# 出发站
from_station_code = data_list[6]
item['from_station_name'] = stations_list[from_station_code]
# 终点站
to_station_code = data_list[7]
item['to_station_name'] = stations_list[to_station_code]
# 出发时间
item['start_time'] = data_list[8]
# 到达时间
item['arrive_time'] = data_list[9]
# 总耗时
item['time_fucked_up'] = data_list[10]
# 商务特等
item['business_class_seat'] = data_list[25] or '--'
# 一等座
item['first_class_seat'] = data_list[31] or '--'
# 二等座
item['second_class_seat'] = data_list[30] or '--'
print item['second_class_seat']
# 软卧
item['soft_sleep'] = data_list[23] or '--'
# 硬卧
item['hard_sleep'] = data_list[28] or '--'
# 硬座
item['hard_seat'] = data_list[29] or '--'
# 无座
item['no_seat'] = data_list[26] or '--'
代码就自己看吧,很简单的 python 基础。
经过简单的组装,就得到了简单的示例程序,下面是完整代码:
# coding=utf-8
from time import sleep
import datetime
import requests
import smtplib
from email.mime.text import MIMEText
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
def query_trains(data):
url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(
data.date, data.form, data.to
)
jsondata = ""
#print requests.get(url).text
while jsondata=="" or jsondata==None:
try:
print(url)
print("try get json")
jsondata = requests.get(url).json()
# print jsondata
except:
jsondata = ""
print("get json error")
sleep(7)
return jsondata
def sort_trains(raw,data):
flag=0
for_sale = []
not_for_sale = []
raw_trains = raw['data']['result']
stations_list = raw['data']['map']
content = "有新的车票啦!!\r\n车票信息如下:\r\n-------------------------\r\n"
content+="运行区间:"+stations_list[data.form]+"---"+stations_list[data.to]+"---"+data.date+"\r\n"
for i in raw_trains:
train_data=i.split("|")
if int(str(train_data[8])[0:2])<18 and int(str(train_data[8])[0:2])>0: #查找下午18点以前的火车
if train_data[0]=="":
print str(train_data[3]+"--"+train_data[8]+"-"+train_data[10]+"-已售空")
else:
if train_data[26] != "" and train_data[26]!="无": # 无座
# print(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] + "-"+train_data[26])+ "-无座有票")
content+=(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] + "-"+train_data[26])+ "-无座有票"+"\r\n")
flag = 1
if train_data[29] != "" and train_data[29]!="无": # 硬座
# print(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] + "-"+train_data[29])+ "-硬座有票")
content +=(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] + "-"+train_data[29])+ "-硬座有票"+"\r\n")
flag = 1
if train_data[30]!="" and train_data[30]!="无": #二等座
# print(str(train_data[3]+"--"+train_data[8]+"-"+train_data[10]+ "-"+train_data[30]) + "-二等座有票")
content +=(str(train_data[3]+"--"+train_data[8]+"-"+train_data[10]+ "-"+train_data[30]) + "-二等座有票"+"\r\n")
flag = 1
content+="-------------------------\n"
content += "时间:"+datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S')+"\r\n"
content += "Powered By:xynling"
if flag==1:
print content
class TrainData:
def __init__(self,form,to,date):
self.form = form
self.to=to
self.date=date
def main():
while True:
if (int(datetime.datetime.now().strftime('%H'))>=6):
td=TrainData('BJP','KMM','2018-10-17')
sort_trains(query_trains(td),td)
sleep(30) #休眠30s继续执行
else:
print(int(datetime.datetime.now().strftime('%H')))
sleep(5)
if __name__ == '__main__':
main()
是循环 30 秒进行查询的。
查询结果如图:
结合邮箱进行微信提醒:
如果放在服务器上运行就能很方便的收到车票提醒啦!
实现原理部分摘自网络,文章原创,转载请注明转载自 ynlflixin 的个人博客!
😄