python火车票查询系统的实现与总结
想法是用python编写一个车票查询工具,可以很好的锻炼一下自己python的网络编程能力。
1、第一步设计这个API的接口:
根据12306的设计我的API接口也要有出发站,目的站,车次类型,日期四部分。
车次类型:
-g 高铁
-d 动车
-t 特快
-k 快速
-z 直达
需要用到的库:
requests,使用 Python 访问 HTTP 资源的必备库。docopt,Python3 命令行参数解析工具。prettytable, 格式化信息打印工具,能让你像 MySQL 那样打印数据。colorama,命令行着色工具
因为我这机子上python版本众多,但默认python版本为2.7,python3的pip3、settools没有安装。
下面安装:
sudo apt-get install python3-setuptools
sudo easy_install3 pip requests docopt prettytable colorama
安装这三个库:
sudo pip3 install
新建tickets.py 文件,代码如下:
# coding: utf-8
""" 命令行火车票查看器
Usage:tickets [-gdtzk] <from> <to> <date>
Options:-h,--help 显示帮助菜单-g 高铁-d 动车-t 特快-k 快速-z 直达
Example:tickets -gd 沈阳 北京 2017-03-01
"""
#command-line-interface
from docopt import docopt
def cli():arguments=docopt(__doc__)print(arguments)
if __name__ == "__main__":cli()
“# coding: utf-8 ”是为了避免输出中文乱码的一种编码方式,确立输出文件为在python3.x之后没有这个问题。
接下来是python命令行解析工具docopt的固定格式,这个工具简洁方便。
“if name == “main“: cli()” 这就代码的作用是当直接运行tickets.py 时会打印命令行参数提示信息。
每个模块都有内置方法name,当直接被调用时为main,被导入使用时为他的文件名。所以这里执行cli().
效果:
2.网站应答分析
打开12306,随便输入时间和地点,最好浏览器为火狐装载firebug插件。点击查询:
消息头信息:注意这个URl:https://kyfw.12306.cn/otn/leftTicket/后加了四个参数,始发站,目的站,时间,和是否半价票。
在抓取的请求和应答中,找到如下图这样的报文,他的参数有始发站,目的站,时间,这样的才是我们要在python中想要获取的数据。但是站点名都是缩写,想想你登12306查火车票, 你输入的是汉字吧, 而我们发现了请求的URL中是车站代码, 这样我们就知道汉字到代码的转换是在前端(JS)完成的, 那么前端源码中肯定有转换对应表.
这个响应信息就是我们想要的:
我们要通过查看源代码找找这个缩写和站点名是怎样对应的。
看看:/otn/resources/js/framework/station_name.js?station_version=1.8997,源是从这里来的,我们也要从这里获取站名对应表,这就是前面说的转换对应表。
新建一个teststation.py用来获取站名代码如下:
# coding: utf-8
import re
import requests
from pprint import pprinturl = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8997'
response = requests.get(url,verify=False)
station = re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)',response.text)
pprint(dict(station),indent=4)
re模块是一个用来检索的一个模块,导入他我们可以把与之匹配的信息通过pprint方法打印出来。requests模块是http请求必用的模块。
之后导入到stations.py 文件中:
python3.5 teststations.py > stations.py
这里边执行我用了python3.5,因为默认的python 为2.7版本,对输出中文不支持。
效果:
对输出的字典文件加个stations名。
现在,用户输入车站的中文名,我们就可以直接从这个字典中获取它的字母代码了。
3、数据的获取
# coding: utf-8"""命令行火车票查看器Usage:tickets [-gdtkz] <from> <to> <date>Options:-h,--help 显示帮助菜单-g 高铁-d 动车-t 特快-k 快速-z 直达Example:tickets 北京 上海 2016-10-10tickets -dg 成都 南京 2016-10-10
"""
#command- line -interface
from docopt import docopt
from stations import stations
import requests
def cli():arguments = docopt(__doc__)from_station = stations.get(arguments['<from>'])to_station = stations.get(arguments['<to>'])date = arguments['<date>']url = 'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(date,from_station,to_station)r = requests.get(url,verify=False)print (r.json())
if __name__ == "__main__":cli()
这段代码大意就是把tickets.py 的参数值赋给三个变量,然后赋给由第二遍得到的URl中,再由get()函数接受数据,打印其JSON格式。
效果是这样的:
分析一下我们可以看到其实得到的数据是四个字典,第三个字典中有嵌套了字典列表:
4、 解析数据
代码如下:
这是根据现在12306网站写的接口,它的接口经常变动。第三步得到的数据形式也总在变化。
# coding: utf-8"""命令行火车票查看器Usage:tickets [-gdtkz] <from> <to> <date>Options:-h,--help 显示帮助菜单-g 高铁-d 动车-t 特快-k 快速-z 直达Example:tickets 北京 上海 2016-10-10tickets -dg 成都 南京 2016-10-10
"""
from docopt import docopt
from stations import stations
import requests
from prettytable import PrettyTableclass TrainsCollection:header = '车次 车站 时间 历时 一等 二等 软卧 硬卧 硬座 无座'.split()def __init__(self, available_trains, options):"""查询到的火车班次集合:param available_trains: 一个列表, 包含可获得的火车班次, 每个火车班次是一个字典:param options: 查询的选项, 如高铁, 动车, etc..."""self.available_trains = available_trainsself.options = optionsdef _get_duration(self,raw_train):duration = raw_train.get('lishi').replace(':','小时')+ '分'if duration.startswith('00'):return duration[4:]if duration.startswith('0'):return duration[1:]return duration@propertydef trains(self):train_no = self.available_trains['station_train_code']initial = train_no[0].lower()if not self.options or initial in self.options:train = [train_no,'\n'.join([self.available_trains['from_station_name'],self.available_trains['to_station_name']]),'\n'.join([self.available_trains['start_time'],self.available_trains['arrive_time']]),self._get_duration(self.available_trains),self.available_trains['zy_num'],self.available_trains['ze_num'],self.available_trains['rw_num'],self.available_trains['yw_num'],self.available_trains['yz_num'],self.available_trains['wz_num'],]yield traindef pretty_print(self):pt = PrettyTable()pt._set_field_names(self.header)for train in self.trains:pt.add_row(train)print(pt)#command- line -interfacedef cli():arguments = docopt(__doc__)from_station = stations.get(arguments['<from>'])to_station = stations.get(arguments['<to>'])date = arguments['<date>']url = 'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(date,from_station,to_station)# 获取参数options = ''.join([key for key, value in arguments.items() if value is True])r = requests.get(url, verify=False)rows = r.json()['data']for row in rows:available_trains = row['queryLeftNewDTO']#print (available_trains)TrainsCollection(available_trains, options).pretty_print()if __name__ == "__main__":cli()
“ @property”
Python中有一个被称为属性函数(property)的小概念,它可以做一些有用的事情。能做以下几点:
将类方法转换为只读属性
重新实现一个属性的setter和getter方法
使用属性函数的最简单的方法之一是将它作为一个方法的装饰器来使用。这可以让你将一个类方法转变成一个类属性。当我需要做某些值的合并时,我发现这很有用。其他想要获取它作为方法使用的人,发现在写转换函数时它很有用。
rows = r.json()
这条代码的后的导出文件:
{
'messages': [],'validateMessagesShowId': '_validatorMessage','data': [{'queryLeftNewDTO':{'controlled_train_flag': '1','yw_num': '--', 'end_station_name': '杭州','from_station_name': '沈阳北', 'yz_num': '--','gr_num': '--','rz_num': '--', 'start_station_name': '哈尔滨', 'train_no': '010000Z17804','location_code': 'B2','swz_num': '--', 'from_station_telecode': 'SBT','lishiValue': '5999','wz_num': '--','start_province_code': '06','tz_num': '--',...}]}
之后使用json函数来匹配字典中的[‘data’]关键字,我们看一下匹配后的导出文件:
rows = r.json()['data']
[{'queryLeftNewDTO':{'controlled_train_flag': '1','yw_num': '--', 'end_station_name': '杭州','from_station_name': '沈阳北', 'yz_num': '--','gr_num': '--','rz_num': '--', 'start_station_name': '哈尔滨', 'train_no': '010000Z17804','location_code': 'B2','swz_num': '--', 'from_station_telecode': 'SBT','lishiValue': '5999','wz_num': '--','start_province_code': '06','tz_num': '--', 'station_train_code': 'Z178','to_station_telecode': 'ZJH','rw_num': '--', 'controlled_train_message': '列车运行图调整,暂停发售', 'from_station_no': '05','yp_info': '', 'arrive_time': '24:00',...]
这是一个列表,我们用for来检索:
for row in rows:available_trains = row['queryLeftNewDTO']
这是我们要的信息了
{'day_difference': '0',
'end_station_telecode': 'AOH','lishiValue': '527',
'controlled_train_flag': '0',
'start_city_code': '0034',
'yb_num': '--',
'lishi': '08:47',
'ze_num': '有','is_support_card': '1',
'tz_num': '无',
'start_station_name': '哈尔滨西','station_train_code': 'G1202',
'yz_num': '--',
'end_station_name': '上海虹桥',
'rz_num': '--',...}
效果图:
python火车票查询系统的实现与总结相关推荐
- python作业火车票订购系统_Python实现12306火车票查询系统
最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都详细给分享出来.(注意使用的是python3) 首先我将最终结果给展示出来: 在cmd命令行执行:py ...
- python作业火车票订购系统_Python脚本实现12306火车票查询系统
最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都具体给共享出来.(注重使用的是python3) 首先我将最终结果给展示出来: 在cmd命令行执行:py ...
- python实现火车票查询_Python脚本实现12306火车票查询系统
最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都详细给分享出来.(注意使用的是python3) 首先我将最终结果给展示出来: 在cmd命令行执行:py ...
- python查询12306余票_Python脚本实现12306火车票查询系统
最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都详细给分享出来.(注意使用的是python3) 首先我将最终结果给展示出来: 在cmd命令行执行:py ...
- python公交查询系统
python公交查询系统 公交查询系统实验可以实现一个方便.快捷的公交信息查询方式.要求实现以下功能:1.线路查询:可以获得要查询公交所通过的各个站点:2.站点查询:通过输入的指定站点查询经过该站点的 ...
- java 火车票查询系统_Java火车票查询系统
[实例简介] Java火车票查询系统 [实例截图] [核心代码] Java火车票查询系统 └── 计156-1第2组 ├── Train.mdb ├── build │ ├── built-jar ...
- 火车票查询系统(一)——利用python实现监控12306余票查询
最近春运高峰,本人从12月开始买过年回家的火车票,然鹅~现实总是那么残酷,放票时间记不住,要么就是不能实时盯着刷票,外面的软件也不知道靠不靠谱,反正是没买到票,所以一怒之下,自己做一个12306余票查 ...
- python 火车票查询,Python3实现火车票查询工具
项目简介:使用Python3抓取12306网站信息提供一个命令行的火车票查询工具.通过该项目的实现,可以熟悉Python3基础及网络变成,以及docopt,requests,prettytable等库 ...
- python 火车票查询_Python,写火车票查看器,你还在担心没票吗?
![image](https://img-blog.csdnimg.cn/img_convert/f18828e9f341911936a88757a9c1d140.webp) 当你想查询一下火车票信息 ...
最新文章
- 谈谈计算机行业的秋招和春招
- Android keystore/Keymaster的代码导读
- 【POJ - 1364】King(差分约束判无解)
- 基于JAVA+SpringMVC+Mybatis+MYSQL的手表销售系统
- 什么?是Transformer位置编码
- 红米note3支持html,红米Note3什么配置参数?红米Note3标配有什么?
- openssl代码领读目录
- CV+Deep Learning——网络架构Pytorch复现系列——classification(一:LeNet5,VGG,AlexNet,ResNet)
- PC Logo入门指南
- paraview参考手册6:远程并行可视化
- mac 键盘失灵_苹果电脑按键失灵怎么办_mac键盘部分按键失灵如何修复-win7之家...
- 极坐标弧长积分公式简单理解 极坐标求面积的公式,dθ 弧长积分公式,rd​原理; 极坐标弧积分
- 通俗易懂物联网(2):物联网的特点
- 彻底解决NSEC病毒
- 判断输入的日期是一年的第几天或者星期几
- php源码中powerby,小龙源码网 - discuz论坛怎么去掉power by discuz版权
- 【局域网音频实时传输、屏幕单播及广播】
- 计算机维修调试高级,计算机安装调试维修四级操作题
- 面试总结+网上查阅的智力题
- react+ts+echarts5.x按需导入实现世界地图