这个小工具通过抓取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实现火车票查询小工具相关推荐

  1. 如何检测python是否安装_布同自制Python函数帮助查询小工具

    比如在学习list.tuple.dict.str.os.sys等模组的时候,利用Python的自带文档可以很快速的全面的学到那些处理的函数.所以这个自带文档功能能够给出学者带来很大的方便之处,进行简短 ...

  2. 自制Python函数帮助查询小工具

    Python的自带文档功能很不错,给与我耳目一新的感觉.如果在CMD中进行"行式编程"编程的话,可以随时随地的查询函数的功能,非常方便.比如在学习list.tuple.dict.s ...

  3. 小工具:天气查询 Vs自定义设置 DevGridControl中GridView排序问题 小工具:火车票查询 小工具:邮件发送 小工具:截图简单图像处理...

    小工具:天气查询 开发一个天气查询的工具主要由两步构成,一是数据的获取,二是数据的展示.  一.数据获取 数据获取又可以分为使用其它公司提供的API和手动抓取其它网站数据. 1. 某公司提供的API ...

  4. python实现火车票查询工具_Python 实现一个火车票查询的工具

    原标题:Python 实现一个火车票查询的工具 作者 sexycoder 本文转载自简书,转载需授权 使用 python 实现一个查询火车票的小工具 主要功能: 输入出发车站,到达车站,时间,然后返回 ...

  5. 【爬虫】用Python爬取去哪儿网热门旅游信息(并打包成旅游信息查询小工具)

    以下内容为本人原创,欢迎大家观看学习,禁止用于商业用途,谢谢合作! ·作者:@Yhen ·原文网站:CSDN ·原文链接:https://blog.csdn.net/Yhen1/article/det ...

  6. python火车票查询工具tkinter_Python 实现一个火车票查询的工具

    原标题:Python 实现一个火车票查询的工具 主要功能: 输入出发车站,到达车站,时间,然后返回所有的车次信息,和余票信息 支持输入附加选项查询不同的火车的类型,比如高铁,动车. #查询上海到北京2 ...

  7. python四级成绩_四六级准考证号模糊查询工具下载-英语四六级准考证号模糊查询小工具下载Python版-西西软件下载...

    想查自己的四六级成绩缺忘了准考证号码?试试英语四六级准考证号模糊查询小工具呗!这是一款由Python爬虫语音编写成的小软件,只需要输入身份号或者准考证前十位数,它可以帮你快速的查询出你的四六级成绩和准 ...

  8. 用Python做了一个法律查询小工具,非常好用

    用Python做了一个法律查询小工具,非常好用 效果展示 准备工作 主要代码 哈喽兄弟,今天给大家分享一个Python tkinter制作法律查询小工具. 光爬虫大家也只能自己用用,就算打包了exe, ...

  9. python实现火车票查询_Python脚本实现12306火车票查询系统

    最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都详细给分享出来.(注意使用的是python3) 首先我将最终结果给展示出来: 在cmd命令行执行:py ...

最新文章

  1. LightOJ 1422:Halloween Costumes(区间DP入门)
  2. 2.【sheel学习】数组
  3. 抓取新浪的每日星座运势
  4. arm linux 自动挂载,ARM-Linux支持并自动挂载U盘
  5. Pashmak and Parmida's problem(树状数组)
  6. Vue成大学核心课程
  7. [Silverlight入门系列]用TransformToVisual和Transform取得元素绝对位置(Location)
  8. 淘沙潜行,数一数英雄的多姿,王者荣耀英雄、皮肤、武器展览
  9. JAVA与GO语言之间应该选择学习哪个?
  10. 入门物联网需要服务器
  11. SSR远程登陆服务器配置
  12. 服务器怎么做好安全防护措施
  13. C语言中数组名的使用总结
  14. Java并发编程之ThreadPoolExecutor源码解析
  15. 【转】我公务员工作七年后的肺腑之言
  16. 萌新成长计划(开篇章)
  17. 正确认识形势 提升信心 增强斗志
  18. 免费制作证件照,这3个在线网站千万别错过
  19. VBoxManager命令解析
  20. 股票数据转换和数据提取软件。

热门文章

  1. Argox(立象)打印机
  2. 基于C#的机器学习--c# .NET中直观的深度学习
  3. php纸牌数据结构,蜘蛛纸牌底牌数据结构图及辅助代码利用
  4. 机器人笔记本清灰_小熏的编程日记 » 愉悦的小机器人调教经历(一):使用笔记本为HTC G4提供无线路由...
  5. 技术丨如何处理有依赖的消息
  6. hp喷墨打印机加连供的处理
  7. 日常所需 - 收藏集 - 掘金
  8. 山西省大学计算机专业排名,山西省:排名前14的大学!山西的大学分为5档,前2档最难考!...
  9. daocloud mysql_GitHub - DaoCloud/php-laravel-mysql-sample
  10. 使用Tableau绘制电影数量与评分的符号地图