python入门实践七:12306火车票查询工具

说明:个人练手python用。
操作系统:window10 x64
IDE:Pycharm 2017.2.2
Python版本:3.6.2
本文参考自:https://www.shiyanlou.com/courses/623/labs/2072/document

一、接口获取

打开12306,在余票查询页面,点击F12,点击查询按钮

余票查询接口获取

通过Network可以查询到本次查询时所有的网络请求接口,这里的第二个接口就是火车票数据查询的接口,如下:

https://kyfw.12306.cn/otn/leftTicket/queryX?leftTicketDTO.train_date=2017-09-25&leftTicketDTO.from_station=ZZF&leftTicketDTO.to_station=KFF&purpose_codes=ADULT

其中:
1、leftTicketDTO.train_date表示查询日期
2、leftTicketDTO.from_station:表示出发地编码
3、leftTicketDTO.to_station:表示目的地编码
4、purpose_codes:表示票的类型,ADULT表示成人,如果是学生,则值为0X00

也就是网页中我们填上去的参数,很好对应上:


接口参数

访问该接口,就可以获取本次查询的全部JSON格式的数据了:

部分数据截图

二、数据分析

把上述比较乱的数据中的result部分(车票部分)存入文本,然后导入到excel(用|分割即可),然后删除没用的列,空列等,看起来就规整多了,像这样:


json数据以|分割导入excel结果图

然后对比着12306上面的查询结果

部分12306查询结果

很容易分析出每列的含义:

查询数据每列的含义

这就是本工具的数据基础,接下来就简单了:
1、使用python请求接口获取数据
2、数据格式调整并展示

三、使用python获取数据

定义方法用于请求接口数据,如下:

def get_json(url, train_date, from_station, to_station, purpose_codes='ADULT'):
    url = url + '?leftTicketDTO.train_date=' + train_date + '&leftTicketDTO.from_station=' + from_station + '&leftTicketDTO.to_station=' + to_station + '&purpose_codes=' + purpose_codes
    req = request.Request(url)
    req.add_header('User-Agent',
                   'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36')
    req.add_header('Cookie',
                   'BLPROV=; JSESSIONID=17F82C085BEAE9774B1D7D18363207AA; route=6f50b51faa11b987e576cdb301e545c4; BIGipServerotn=1473839370.50210.0000; fp_ver=4.5.1; RAIL_EXPIRATION=1505522206734; RAIL_DEVICEID=ngfa0xXXc43Aw-RdePQiYKNAXLxgF_0NC4u29FDPVr73XbEdk2jAZXdZmGwbMs5tmX28EVf3pqQWywtJRANyU-F1F4o1jEN2J8gI5mQVerkJAel9E5ACri_F-7hggwk7zmV0IkRNjiH5CA0RFxBPLTsBkmBvAJ9_; current_captcha_type=C; _jc_save_fromStation=%u90D1%u5DDE%2CZZF; _jc_save_toStation=%u5F00%u5C01%2CKFF; _jc_save_fromDate=2017-09-25; _jc_save_toDate=2017-09-25; _jc_save_wfdc_flag=wf')
    with request.urlopen(req) as f:
        return json.loads(f.read())

注意这里的request header中要添加cookie信息,否则报405错误!感觉两者没有直接关系,但结果就是这样,不知道为啥。

然后根据上面分析的结果,json解析及拆分展示如下:

def list_ticket():
    json_result = get_json('https://kyfw.12306.cn/otn/leftTicket/queryX', '2017-09-25', 'ZZF', 'KFF')
    list_tickets = json_result['data']['result']
    print("车次", "始发站", "终点站", "出发站", "到达站", "出发时间", "到达时间", "历时", "商务座", "一等座", "二等座", "软卧", "硬卧", "软座", "硬座", "无座",
          "备注")
    for ticket in list_tickets:
        list_ticket_item = ticket.split('|')
        print(list_ticket_item[3], list_ticket_item[4], list_ticket_item[5], list_ticket_item[6], list_ticket_item[7],
              list_ticket_item[8], list_ticket_item[9], list_ticket_item[10], list_ticket_item[32], list_ticket_item[31],
              list_ticket_item[30], list_ticket_item[23], list_ticket_item[28], list_ticket_item[24],
              list_ticket_item[29], list_ticket_item[26], list_ticket_item[11])

运行输出结果为:

查询结果输出

四、车站名称和编码

上述步骤虽然查询到了结果,但是有两方面的问题
1、车站名称应该显示中文名称,而不是编码,并且应该能查询任意两站的火车票信息。
2、直接print打印格式比较乱

先来说第一点:
余票查询页面上右击--查看源代码--大概962行,可以看到如下js文件:

全部站名及编码

点击该js文件链接可以看到
全部站名及编码

该文件包含了全部的站名称和对应编码,根据该文件,前端页面把从后台查询到的编码转为了火车站中文名称。

写个python把站名和对应编码拿下来:

import re
import requests
from pprint import pprint

url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9025'
response = requests.get(url, verify=False)
stations = re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
print(dict(stations), indent=4)

# 反转dict
dict_res = dict(stations)
dict_res = dict(zip(dict_res.values(), dict_res.keys()))
print(dict_res)

结果如下:

站名及编码
编码及站名

把这些数据作为字典,存在py文件中,就可以直接当dict用了。

经过上述改进,输出结果如下:

郑州到北京车票信息查询

五、格式化

可以使用第三方模块prettytable对控制台输出结果美化,结果如下:

美化后的结果

六、补充说明

1、如果在请求HTTPS协议时碰到证书问题,则在最前面加上一句:

ssl._create_default_https_context = ssl._create_unverified_context

2、可以使用colorama模块对控制台进行着色处理,这个没做。

七、完整代码

完整代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容