Python实现火车票查询小工具
这个小工具通过抓取12306网站提供的数据并进行解析,从而实现通过命令行的方式查询火车票余票数的功能。主要运用了docopt,requests,prettytable,colorama的库函数,达到简单熟悉Python3网络编程的目的。
运行效果如下:
首先,我们用docopt这个库来解析Python的命令行参数,docopt可以按我们在文档字符串中定义的格式来解析参数,比如我们在代码中写下以下内容:
# coding: utf-8"""命令行火车票查看器Usage:tickets [-gdtkz] <from> <to> <date>Options:-h,--help 显示帮助菜单-g 高铁-d 动车-t 特快-k 快速-z 直达Example:tickets 北京 上海 2017-10-22tickets -dg 成都 南京 2017-10-22
"""
from docopt import docoptdef cli():"""command-line interface"""arguments = docopt(__doc__)print(arguments)if __name__ == '__main__':cli()
上面的程序中, docopt 会根据我们在 docstring 中的定义的格式自动解析出参数并返回一个字典,也就是 arguments, 我们打印出了这个字典的内容。
接下来是获取数据,让我们先打开12306的官网,进入余票查询页面,随便查询一次从北京到上海的车次,然后按F12打开开发者工具,选中Network一栏,在调试工具观察下请求和响应:
从图中可以很容易找到请求数据的URL:https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-10-23&leftTicketDTO.from_station=SHH&leftTicketDTO.to_station=BJP&purpose_codes=ADULT
这个URL中包含了日期、始发站、终点站和票种这4个参数。
再来看看响应,返回的是JSON类型的数据格式:
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"result":["bNRE8c%2BXEBWxgoY2%2BwD2EXNd9X3Vq%2Fsu%2F52Suzj1D5G04NUZC24nL3WDpgz1Ckjnylc6bjF63ZNe%0AQk%2F9%2B%2FYqE9Q5%2BXy2jBSf7CfRkAPcXYXsOUKWBp%2FBcsJhOK%2FmHgWqi%2Fx9RNh6I0hKLX1x6BIRQTwe%0AuRsDUVzFr2NeUUWimFq6ufEHCk2aPMJ4td%2FwykJHpgH4e02rqqdG7yOjTp44mSe9GdE8A%2FpDYPpt%0A%2FAsST4Q%2FbFk5|预订|24000000G704|G7|VNP|AOH|VNP|AOH|19:00|23:24|04:24|Y|PqkHst0aswwEKvaCVR7Uapmm3DXK8paJmjU9NSfvbnlBvCUt|20171022|3|P3|01|04|1|0|||||||||||无|无|3||O0M090|OM9","KoomdrHNm1Tx9kVBmvC7at4PpS5oSRXJfhdz%2FovAwoQDu38vAtxUk81JC5cbJRRzq46f%2BKv%2F1ISL%0AaHheZGr0eeDPqKg7ncxbkQRDKzQGJ4zm83g9PrLORv44LatQAMLcQbA9wt97ybVPrqiPAB7H5Cmy%0AiRtowmYcyhJkYvsIE8k1BkF4%2FVa7JPQMt7C2GQ4zbM2roP6V3Pq7frCqPy7xzeDzWwkgXcGDzmac%0Ag2jf3cG7VBs%2F|预订|24000000G900|G9|VNP|AOH|VNP|AOH|19:05|23:39|04:34|Y|pCGsb0O3dQbaBabrV4TJpg3t2pEoGaN%2Fhnbk74S03WODkZrD|20171022|3|P4|01|05|1|0|||||||||||无|1|11||O0M090|OM9","VWaI9EbpmOx%2BnPniU%2FgnFSU1FLqfyzaxu9pG27hFAtdcK%2FRdZAhRGUZeULWZGW%2F%2BOWSQd6n%2FnmFk%0AT83rJOW2qux1lQnKpPPTTLiLfbfEde21CBl2kueRvsA0meHGCfzY8VuIb6qHa5LkKvfLW8hn7q2F%0Akv728gU9%2FdBCTUXZdlc1zwGG%2FC2tsw5lounA0HQgjbfh0QjHOm8c81MfrEJ%2F81YXqNsPC6o4Tavp%0AUrDLzH1WiT4C48eUkBTTMjTx1QLG|预订|240000T1090W|T109|BJP|SHH|BJP|SHH|19:31|10:43|15:12|Y|aR5INYGawqzJ86i%2Fphbwbtd4ANudQ7765pg5VGHbH6Lnq8GodCgTCyGDmlbzTfQHQmqHJ8Wr%2B7s%3D|20171022|3|P4|01|08|0|0||2||无|||有||无|无|||||1040601030|14613","1k5vSGjsyUKKmnF3wjKsUjewdk7U69QKoVXEyQX2kMIKHIUYvqhE23w3IBA0epXq4CTrWtDQP7nz%0AQYIpWUj3Jaa276MN758C6iMAqkKbis6XLa%2B53stldGua11M3QTMDuczGfeVlVxkhlb00OfUAQsw1%0ASd1HGtLCeTuiwDWyt1aH0mcgx0ef7MdtrO2v%2BqxHarnz749ZZx0ikJslYx9HS%2Fo6bKoIXwRja64E%0AIRe8dPM%3D|预订|240000D3130S|D313|VNP|SHH|VNP|SHH|19:34|07:41|12:07|Y|zS7aXAcrDA9MGtYGt1qWAEjXj2KmL52pzmkIbYCX40Gbf8xJ|20171022|3|P3|01|04|0|0||||有|||无||||无||||O0O040|OO4","qHG7W4%2BkkK5wYlrA40Nad8qpBSQ62tAEoxqMmz8ILRPATCwg8tfv%2BwPfQtykNYj2ujediGM%2Bpfz0%0AnWWZf0ELHkPP1WFmc3oFgLsa2B0WzUbKUrI79%2Fe%2BEk%2FuI53VZclFnKpbhchiJ4Ftl67D7Q77pt%2Bv%0AeCwF1tP7sPQUd4coP%2Bdb3%2BQg0oE9sDXmhVjJNLUOHUz8MRoyIJBfV7D5cWvK49I9x6A%3D|预订|240000D3110I|D311|VNP|SHH|VNP|SHH|21:16|09:08|11:52|Y|WtArzt%2B3giRh6uPIHTnXnMFJMlFHLnOh|20171022|3|P2|01|04|0|0||||无||||||||||有|F040|F4","tSc61q3CsO1s7q4uL0veATeCmit1eJdnG1OBVn8VE8t9ow42zXNLbEeOppvc5A38DEQ%2BdYkMKMmq%0AD8krmmrRo1keh5YicUd3D9r4blEwKcaUnQ71pTMaJYxLRF5963S12ZYUXhD%2BULgWWQrKbT%2BuIpkg%0ATi3IREK9lJd0M5GTl4d9kA9ad7QsoyYPGe0cZAg6UN80GrcEUt5rMSaWfRR%2B1WVyJF8oq9dmE4mr%0AkPDK7ZA%3D|预订|240000D3210C|D321|VNP|SHH|VNP|SHH|21:23|09:13|11:50|Y|24U826GG6aSol8XIx79SYxePep2ul8PFdg5XcV9ThH1wMK0X|20171022|3|P2|01|04|0|0||||有|||无||||无||||O0O040|OO4"],"flag":"1","map":{"AOH":"上海虹桥","BJP":"北京","VNP":"北京南","SHH":"上海"}},"messages":[],"validateMessages":{}}
可以看到一列火车的数据用 Python 的语言说就是一个字典,我们需要解析字典中的 "data"对应的"result"键里的内容。再观察这些数据,其中站点对应的名称并非中文,而是大写英文代号,我们可以继续在F12开发者工具里找到对应的station名称的文件:
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9028
这个文件里的JSON内容就包含了所有车站的中文名、拼音、简写和代号等信息,我们先用re正则表达式写个小脚本来提取出所要的信息,新建stations_parse.py文件:
import re, requests
from pprint import pformaturl = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9028'
response = requests.get(url, verify=False)
stations = re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
str = pformat(dict(stations), indent=4)f = open("stations.py","w",encoding='utf-8')
f.write(str)
f.close()
运行这个脚本,它将以字典的形式返回所有车站和它的大写字母代号,并输出到stations.py中。打开stations.py文件,完善字典的名称和文件头:
# -*- coding: utf-8 -*-
stations = { '一间堡': 'YJT','一面坡': 'YPB','一面山': 'YST','七台河': 'QTB','七甸': 'QDM','七营': 'QYJ','七里河': 'QLD','万乐': 'WEB','万发屯': 'WFB','万宁': 'WNQ','万州': 'WYW','万州北': 'WZE','万年': 'WWG','万源': 'WYY','三义井': 'OYD','三井子': 'OJT',
......
继续,封装一个简单的类来解析数据,其中,我们运用了colorama这个库进行命令行字体着色,运用了prettytable库来将数据进行格式化打印输出:
class TrainCollection:header = '车次 起始站 终点站 出发时间 到达时间 历时 一等座 二等座 软卧 硬卧 硬座 无座'.split()def __init__(self, available_trains, options):"""查询到的火车班次集合:param available_trains:一个列表,包含可获得的火车班次,每个火车班次是一个字典:param options:查询的选项,如高铁,动车,etc..."""self.available_trains = available_trainsself.options = optionsdef _color_print(self, item, color):return color + item + colorama.Fore.RESET@propertydef train(self):for item in self.available_trains['result']:item = item.split('|')train_no = item[3]# 过滤为空或者是在过滤选项中if not self.options or train_no[0] in self.options:start_station = self.available_trains['map'].get(item[6])end_station = self.available_trains['map'].get(item[7])departure = item[8]arrival = item[9]duration = item[10]yd = item[-4]ed = item[-3]rw = item[23]yw = item[-7]yz = item[-6]wz = item[26]row = [train_no,self._color_print(start_station, colorama.Fore.MAGENTA),self._color_print(end_station, colorama.Fore.GREEN),self._color_print(departure, colorama.Fore.MAGENTA),self._color_print(arrival, colorama.Fore.GREEN),duration, yd, ed, rw, yw, yz, wz]yield rowdef pretty_print(self):pt = PrettyTable()pt._set_field_names(self.header)for train in self.train:pt.add_row(train)print(pt)
最后,我们将上述过程进行汇总并将结果输出到屏幕上:
def cli():""" command-line interface"""arguments = docopt(__doc__)# print(arguments)from_station = stations.get(arguments['<from>'])to_station = stations.get(arguments['<to>'])date = arguments['<date>']options = ''.join([k for k, v in arguments.items() ifv is True])# print(from_station, to_station, date)# 构建URLurl = "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)# 添加verify=False参数不验证证书r = requests.get(url, verify=False)r_json = r.json()['data']TrainCollection(r_json, options).pretty_print()
完整代码见:
ticket
Python实现火车票查询小工具相关推荐
- 如何检测python是否安装_布同自制Python函数帮助查询小工具
比如在学习list.tuple.dict.str.os.sys等模组的时候,利用Python的自带文档可以很快速的全面的学到那些处理的函数.所以这个自带文档功能能够给出学者带来很大的方便之处,进行简短 ...
- 自制Python函数帮助查询小工具
Python的自带文档功能很不错,给与我耳目一新的感觉.如果在CMD中进行"行式编程"编程的话,可以随时随地的查询函数的功能,非常方便.比如在学习list.tuple.dict.s ...
- 小工具:天气查询 Vs自定义设置 DevGridControl中GridView排序问题 小工具:火车票查询 小工具:邮件发送 小工具:截图简单图像处理...
小工具:天气查询 开发一个天气查询的工具主要由两步构成,一是数据的获取,二是数据的展示. 一.数据获取 数据获取又可以分为使用其它公司提供的API和手动抓取其它网站数据. 1. 某公司提供的API ...
- python实现火车票查询工具_Python 实现一个火车票查询的工具
原标题:Python 实现一个火车票查询的工具 作者 sexycoder 本文转载自简书,转载需授权 使用 python 实现一个查询火车票的小工具 主要功能: 输入出发车站,到达车站,时间,然后返回 ...
- 【爬虫】用Python爬取去哪儿网热门旅游信息(并打包成旅游信息查询小工具)
以下内容为本人原创,欢迎大家观看学习,禁止用于商业用途,谢谢合作! ·作者:@Yhen ·原文网站:CSDN ·原文链接:https://blog.csdn.net/Yhen1/article/det ...
- python火车票查询工具tkinter_Python 实现一个火车票查询的工具
原标题:Python 实现一个火车票查询的工具 主要功能: 输入出发车站,到达车站,时间,然后返回所有的车次信息,和余票信息 支持输入附加选项查询不同的火车的类型,比如高铁,动车. #查询上海到北京2 ...
- python四级成绩_四六级准考证号模糊查询工具下载-英语四六级准考证号模糊查询小工具下载Python版-西西软件下载...
想查自己的四六级成绩缺忘了准考证号码?试试英语四六级准考证号模糊查询小工具呗!这是一款由Python爬虫语音编写成的小软件,只需要输入身份号或者准考证前十位数,它可以帮你快速的查询出你的四六级成绩和准 ...
- 用Python做了一个法律查询小工具,非常好用
用Python做了一个法律查询小工具,非常好用 效果展示 准备工作 主要代码 哈喽兄弟,今天给大家分享一个Python tkinter制作法律查询小工具. 光爬虫大家也只能自己用用,就算打包了exe, ...
- python实现火车票查询_Python脚本实现12306火车票查询系统
最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都详细给分享出来.(注意使用的是python3) 首先我将最终结果给展示出来: 在cmd命令行执行:py ...
最新文章
- LightOJ 1422:Halloween Costumes(区间DP入门)
- 2.【sheel学习】数组
- 抓取新浪的每日星座运势
- arm linux 自动挂载,ARM-Linux支持并自动挂载U盘
- Pashmak and Parmida's problem(树状数组)
- Vue成大学核心课程
- [Silverlight入门系列]用TransformToVisual和Transform取得元素绝对位置(Location)
- 淘沙潜行,数一数英雄的多姿,王者荣耀英雄、皮肤、武器展览
- JAVA与GO语言之间应该选择学习哪个?
- 入门物联网需要服务器
- SSR远程登陆服务器配置
- 服务器怎么做好安全防护措施
- C语言中数组名的使用总结
- Java并发编程之ThreadPoolExecutor源码解析
- 【转】我公务员工作七年后的肺腑之言
- 萌新成长计划(开篇章)
- 正确认识形势 提升信心 增强斗志
- 免费制作证件照,这3个在线网站千万别错过
- VBoxManager命令解析
- 股票数据转换和数据提取软件。
热门文章
- Argox(立象)打印机
- 基于C#的机器学习--c# .NET中直观的深度学习
- php纸牌数据结构,蜘蛛纸牌底牌数据结构图及辅助代码利用
- 机器人笔记本清灰_小熏的编程日记 » 愉悦的小机器人调教经历(一):使用笔记本为HTC G4提供无线路由...
- 技术丨如何处理有依赖的消息
- hp喷墨打印机加连供的处理
- 日常所需 - 收藏集 - 掘金
- 山西省大学计算机专业排名,山西省:排名前14的大学!山西的大学分为5档,前2档最难考!...
- daocloud mysql_GitHub - DaoCloud/php-laravel-mysql-sample
- 使用Tableau绘制电影数量与评分的符号地图