一、实验目的
平时生活中要查找火车票,一般步骤:先打开12306网站或者APP,但是这样比较麻烦。能不能直接输入一行代码,就可以直接找到我们需要的火车票信息呢?本实验就是用python爬虫,写一个命令行版的火车票查看器,只需要敲一行命令,就能够或许我们想要的信息。
二、实验的总体设计
step1:pip安装实验需要的第三方库
step2:用docopt库,获取命令行参数信息
step3:获取火车票对应的代码信息
step4:通过构造请求链接,获取车票信息
step5:解析返回的链接信息
step6:将返回的车站代码替换成中文
step7:显示设置
三、代码实现
step1:pip安装实验需要的第三方库
- docopt:
- requests:
- prettytable:
- pprint:
- colorama:
1、以管理员身份运行cmd(在安装的时候能省去一些麻烦,比如python安装的不是在C盘,安装第三方库更加的迅速)
2、 pip install docopt
安装这些代码
3、 输入pip list查看这些文件是否安装完毕,如下图所示:
step2:用docopt库,获取命令行参数信息
docopt官网
docopt是一个命令行接口描述语言,用于定义命令行程序的各项参数,并且生成一个处理分析参数的分析器。
本质上是在 Python 中引入了一种针对命令行参数的形式语言,在代码的最开头使用 “”“文档注释的形式写出符合要求的文档,就会自动生成对应的parse,体验非常赞。
"""命令行火车票查看器
Usage:
tickets [-gdtkz] <from> <to> <date>
"""
from docopt import docopt
arguments = docopt(__doc__)
print(arguments['<from>'])
print(arguments['<to>'])
print(arguments['<date>'])
本实验中,只需要输入
E:\Github\test>python test_docopt.py -dg 云南 丽江 2018
即可得到相应的三个返回值arguments[‘’],arguments[‘’],arguments[‘’],用于后面的链接构造
step3: 获取火车票对应的代码信息
在火车票查询的html网页中寻找station_version,如下图所示:
再网页中输入如下代码,即可查找到到车站代码:
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9051
但返给我们的是个json格式的文件,如下图所示:
我们用requests.get(url),获取json文件
使用正则表达式提取出相应的车站和代码,以字典的形式放在一个station的变量中,并且将其放入stations.py文件中,以供调用。这里需要使用pprint这的第三方库,更好的打印字典。
cmd中运行:
python parse_station.py > station1.py
将这个字典存入到stations.py文件当中
这里到stations.py添加字典名
step4:通过构造请求链接,获取车票信息
当我们登陆12306,点击搜索的时候,浏览器传递给服务器的是一个链接,通过这个链接获取我们想要的信息,我们需要的就是构造这个链接,并且解析传递回来的信息
获取火车票查询url
每次点击12306的查询,浏览器就会向网站发送一个请求信息:https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2018-05-02&leftTicketDTO.from_station=WHN&leftTicketDTO.to_station=SZN&purpose_codes=ADULT
其格式如下:
https://kyfw.12306.cn/otn/leftTicket/query?
leftTicketDTO.train_date=2018-05-02
&leftTicketDTO.from_station=WHN
&leftTicketDTO.to_station=SZN
&purpose_codes=ADULT
由以上四个部分组成,在这里,我们需要提供出发站代码,目的站代码以及出发时间信息
我们输入的是中文,但出发站和目的站代码是相应的缩写,需要进行替换
step5:解析返回的链接信息
我们获得的是json格式的数据
这里最困难的就是找到对应的数据信息
网页html源码中,寻找class对应的id,再到对应js中寻找每个元素对应的信息
这里可以根据对应的缩写大致确定一些值,其他的只能通过一个个试了(其中动卧是,上海-重庆-成都,这条线上面的)
这里面cq(0)~cq(36)显示了相关的信息
step6:将返回的车站代码替换成中文
new_dict = {v : k for k, v in dict.items()}
step7:显示设置
用PrettyTable来显示对应值
https://blog.csdn.net/codeway3d/article/details/52798804
代码1:获取车票信息
parse_stations.py
import re # 用正则表达式提取信息
import requests # 获取网页信息
from pprint import pprint # 整齐显示
url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9051'
response = requests.get(url)
stations = re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
pprint(dict(stations), indent=4)
> python parse_stations.py > stations.py
代码2:车票显示
tickets.py
# coding: utf-8
"""命令行火车票查看器
Usage:
tickets [-gdtkz] <from> <to> <date>
"""
import requests # 抓取车票信息
from docopt import docopt # 命令行接口描述语言
from stations import stations # 从stations.py中输入stations这个字典,用于车站和代码的转换
from prettytable import PrettyTable # 格式化打印车票信息
def cli():
arguments = docopt(__doc__) # 将命令行输入值放入arguments字典中
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
) # 生成12306访问链接
r = requests.get(url) # 获取放回的车站信息,是json类型
available_trains = r.json()['data']['result'] # 提取json中的有用车站信息,准备显示
table = PrettyTable('车次 出发站 到达站 出发时间 到达时间 历时 '
'商务座 一等 二等 高级软卧 软卧 动卧 硬卧 软座 硬座 无座 其他'.split()) #显示列表
new_stations = {v: k for k, v in stations.items()} # 将stations中的keys和value交换位置,中文显示出发站和到达站
for raw_train in available_trains: # 开始逐行显示信息
data_list = raw_train.split('|') # 提取每趟列车的信息
table.add_row( # 提取列表中的信息
[data_list[3],
new_stations[data_list[6]],
new_stations[data_list[7]],
data_list[8],
data_list[9],
data_list[10],
data_list[32],
data_list[31],
data_list[30],
data_list[21],
data_list[23],
data_list[33],
data_list[28],
data_list[24],
data_list[29],
data_list[26],
data_list[22]])
print(table) # 打印信息
if __name__ == '__main__':
cli()