项目介绍:利用Python3抓取12306网站信息,提供命令行火车票查询工具。通过本项目的实现,可以熟悉Python3和网络编程的基础知识,以及docopt、requests、prettytable等库的使用。该项目由实验楼的小蜗牛发布。项目在线练习地址为:Python3实现火车票查询工具。可以直接下载代码使用教程中的demo。一、实验简介当你想查看火车票信息时,你还在12306的官网吗?或者打开手机里的APP?下面我们用Python写一个命令行版的火车票查看器,只要在命令行敲一行就可以得到你想要的火车票信息!如果您刚刚掌握了Python的基础知识,这将是一个很好的小练习。1.1知识点Python3基础知识综合应用docopt、requests和prettytable库的使用1.2效果截图2.界面设计应用是写给别人用的,哪怕只是给自己用。所以,首先,你应该想好你要如何使用它?让我们给这个小应用程序起个名字。既然是用来查询票务信息的,那我们就叫tickets吧。我们希望用户只需输入出发站、到达站和日期就可以得到他们想要的信息。比如查询8月25日上海到北京的剩余火车票,我们只需要输入:$ticketsshanghaibeijing2016-08-25注:由于实验楼环境不能输入中文,所以我们的参数设计形式为拼音。想想这里用拼音有没有坏处?抽象这个接口得到:$ticketsfromtodate另外还有各种火车类型,high-speedrail,High-speedtrain,express,fastanddirect,我们希望提供只查询特定类型或特定类型火车的选项,所以我们应该有如下选项:-ghigh-speedrail-dbullettrain-texpress-kfast-zdirecthere几个选项应该可以组合,所以,最后我们的界面应该是这样的:$tickets[-gdtkz]fromtodate接口已经确定,剩下的就是实现它。3、代码实现首先安装实验需要的库:$sodopiinstallrequestsprettytabledocoptrequests,不用介绍,是用Python访问HTTP资源的必备库。docopt,Python3命令行参数解析工具。prettytable,一个格式化信息打印工具,可以让你像MySQL一样打印数据。3.1解析参数Python有很多命令行参数解析工具,比如argparse、docopt、click,这里我们选择docopt,一个简单易用的工具。docopt可以根据我们在docstring中定义的格式来解析参数,比如我们在tickets.py中:注意:实验楼不能输入中文,参数后面的中文可以用拼音代替。#coding:utf-8"""Trainticketsqueryviacommand-line.Usage:tickets[-gdtkz]Options:-h,--help显示帮助菜单-gHigh-speedrail-dMotiontrain-tExpress-kquick-z直接到Example:ticketsbeijingshanghai2016-08-25"""fromdocoptimportdocoptdefcli():"""command-lineinterface"""arguments=docopt(__doc__)print(arguments)if__name__=='__main__':cli()下面我们运行这个程序:$python3tickets.pybeijingshanghai2016-08-25我们得到如下结果:3.2获取已经解析的数据参数下面是如何获取数据,也是最重要的部分。首先,我们打开12306,进入余票查询页面。如果你使用Chrome,按F12打开开发者工具,选择网络栏,在查询框中输入上海到北京,日期为2016-08-25。点击查询,我们在调试工具中,发现查询系统居然请求了这个网址:https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate=2016-07-01&from_station=SHH&to_station=BJP并以JSON格式返回数据!接下来的问题就简单了,我们只需要构造请求URL,然后解析返回的Json数据即可。但是我们发现url中的from_station和to_station并不是汉字或者拼音,而是一个编码,而我们要输入的是汉字或者拼音,怎么得到编码呢?我们打开网页的源代码看看有没有什么发现。果然在网页中找到了这个链接:https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8955里面好像有所有站的中文名称和拼音,信息例如缩写和代号。但是这些信息都挤在一起,我们只想要车站的拼音和大写字母的代码信息,怎么办?正则表达式就是答案,我们写一个小脚本来匹配和提取想要的信息,在parse_station.py中:#coding:utf-8importreimportrequestsfrompprintimportpprinturl='https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8955'text=requests.get(url,verify=False)stations=re.findall(r'([A-Z]+)\|([a-z]+)',text)stations=dict(stations)stations=dict(zip(stations.values(),stations.keys()))pprint(stations,indent=4)注意上面的正则表达式匹配结果转换成字典后,字典的key是一个大写的大写字母,显然不是我们想要的结果,所以我们使用一个transformation将key值依次进行转换。我们运行这个脚本,它会以字典的形式返回所有站点及其大写字母代码,我们将结果重定向到stations.py,$python3parse_station.py>stations.py我们在这个字典中添加一个名称,stations,最后,stations.py文件是这样的:现在,当用户输入站的中文名称时,我们可以直接从这个字典中得到它的字母代码:...fromstationsimportstationsdefcli():arguments=docopt(__doc__)from_staion=站。get(arguments[''])to_station=stations.get(arguments[''])date=arguments['']#buildURLurl='https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate={}&from_station={}&to_station={}'.format(date,from_staion,to_station)万事俱备,我们请求这个URL获取数据吧!这里我们使用requests这个库,它提供了一个非常简单易用的接口,...importrequestsdefcli():...#addverify=False参数不验证证书r=requests.get(url,verify=False)print(r.json())从结果中我们可以观察到需要进一步提取与票证相关的信息:defcli():...r=requsets.get(url);rows=r.json()['data']['datas']3.3解析数据我们封装了一个简单的类来解析数据:fromprettytableimportPrettyTableclassTrainCollection(object):#显示车次、出发/到达站、出发/到达时间、时长、首-一等座,二等座,软卧,硬卧,硬座header='trainstationtimedurationfirstsecondsecondsoftsleephardsleephardsit'.split()def__init__(self,rows):self.rows=rowsdef_get_duration(self.row):"""获取火车行程的运行时间"""duration=row.get('lishi').replace(':','h')+'m'ifduration.startswith('00'):returnduration[4:]ifduration.startswith('0'):returnduration[1:]returnduration@propertydeftrains(self):forrowinself。rows:train=[#车次row['station_train_code'],#出发、到达站'\n'.join([row['from_staion_name'],row['to_station_name']]),#出发、到达时间'\n'.join([row['start_time'],row['arrive']]),#上次self._get_duration(row),#一等座排['zy_num'],#二等座排['ze_num'],#软卧行['rw_num'],#软坐行['yw_num'],#硬坐行['yz_num']]yieldtraindefpretty_print(self):"""数据已获取,剩下的就是提取我们想要的信息并显示它`prettytable`这个库允许我们像MySQL数据库一样格式化和显示数据。"""pt=PrettyTable()#设置每列的标题pt._set_field_names(self.header)fortraininself.trains:pt.add_row(train)print(pt)3.4显示结果最后我们总结一下上面的过程,得到结果输出到屏幕:...classTrainCollection:......defcli():arguments=docopt(__doc__)from_staion=stations.get(arguments[''])to_station=stations.get(arguments[''])date=arguments['']#BuildURLurl='https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate={}&from_station={}&to_station={}'.format(date,from_staion,to_station)r=requests.get(url,verify=False)rows=r.json()['data']['datas']trains=TrainCollection(rows)trains.pretty_print()if__name__=='__main__':cli()3.5最后一米走到这里,程序主体已经完成,但是上面打印出来的结果是黑白的,很无聊,我们来给它上色它:defcolored(color,text):table={'red':'\033[91m','green':'\033[92m',#nocolor'nc':'\033[0'}cv=table.get(颜色)nc=table.get('nv')return''.join([cv,text,nc])修改程序,红色显示出发站和出发时间,绿色显示到达站和到达时间:...'\n'.join([colored('green',row['from_staion_name'])colored('red',row['to_station_name'])]),'\n'.join([colored('green',row['start_time'])colored('red',row['arrive_time'])]),...4。小结本课程使用Python3抓取12306网站信息,提供命令行火车票查询工具。通过本项目的实现,可以学习和实践Python3基础知识和网络编程,以及docopt、requests、prettytable等库的使用。有兴趣的同学可以实现更多的扩展功能:显示商务座位,增加无座位参数支持,用户可以指定车种支持更多的时间格式,如:20161010本项目完整代码和demo可以在实验室查看展示搭建在线完成,马上【开始实验】更多Python经典项目:Python全教程