效果圖
-
1.只查詢動車票
-
2.查詢所有票
Github鏈接
代碼鏈接為:https://github.com/happyte/tickets
接口設(shè)計
- 1.查詢火車票定鸟,需要出發(fā)地點均牢,目的點,日期和所乘列類型這幾個參數(shù),因此設(shè)計出的接口為
python3 tickets.py [-gdtkz] <from> <to> <date>
,[-gdtkz]
代表查詢的火車類型亿汞,該參數(shù)可疊加,例如-gd代表查詢所有的動車和高鐵揪阿。 - 2.python的docopt模塊可以解析命令行的參數(shù)疗我,代碼如下:
"""命令行火車票查看器
Usage:
tickets [-gdtkz] <from> <to> <date>
Options:
-h,--help 顯示幫助菜單
-g 高鐵
-d 動車
-t 特快
-k 快速
-z 直達(dá)
Example:
tickets 北京 上海 2016-10-10
tickets -dg 成都 南京 2016-10-10
"""
from docopt import docent
def cli():
arguments = docopt(__doc__)
print(arguments)
if __name__ == '__main__':
cli()
- 3.在命令行輸入命令
python3 tickets.py -dg 成都 上海 2017-02-10
輸出的結(jié)果如下:
獲取12306數(shù)據(jù)
-
1.用谷歌的chrome瀏覽器抓取下網(wǎng)頁的數(shù)據(jù)
從上圖中發(fā)現(xiàn)請求的url后面跟了4個參數(shù)咆畏,分別為leftTicketDTO.train_date=2017-02-07
、leftTicketDTO.from_station=CDW
吴裤、leftTicketDTO.to_station=SHH
旧找、purpose_codes=ADULT
四個參數(shù)。 -
2.再抓取下response,結(jié)果如下:
所有的車次信息都在data這個字典中麦牺,0-10這個分別包含了每趟車的所有信息钮蛛。
-
3.在請求的url中出發(fā)點和目的地都是英文縮寫,例如上面的
CDW
和SHH
剖膳,而我們在命令行中輸入的是中文魏颓,那么需要通過中文查找到對應(yīng)的英文縮寫,這個用chrome抓取到的數(shù)據(jù)好像沒找到吱晒。那么查看下網(wǎng)頁源代碼
點擊進(jìn)入第一個station_version=1.8994這個文件甸饱,進(jìn)入之后看到該文件是所有車站對應(yīng)的中文和英文縮寫,但是只需要提取中文和英文的大寫縮寫仑濒,編寫一個正則表達(dá)式提取叹话。另外新建一個文件叫parse_station.py,代碼如下:
# -*- coding:utf-8 -*-
import re
import requests
from pprint import print
url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8994'
response = requests.get(url, verify=False) # verify=False不驗證證書
stations = re.findall(u'([\u4e00-\u9fa5]+)+\|([A-Z]+)', response.text)
pprint(dict(stations), indent=4) # indent代表縮進(jìn)
- 4.在命令行執(zhí)行
python3 parse_station.py > stations.py
墩瞳,就新建了一個stations.py文件里面生成了一個中文和英文縮寫對應(yīng)的字典驼壶,如下所示:
獲取需要的信息
- 1.構(gòu)造url請求套鹅,導(dǎo)入上面生成的stations.py文件
from stations import stations
def cli():
arguments = docopt(__doc__)
from_station = stations.get(arguments['<from>'])
to_staion = stations.get(arguments['<to>'])
date = arguments['<date>']
url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date={}&leftTicketDTO.' \
'from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.\
format(date, from_station, to_staion)
response = requests.get(url, verify=False)
- 2.得到請求的json應(yīng)答防楷,因為上面說了所有的列車信息都在data字典內(nèi)部,因此需要的信息在
response.json()['data']
中怠噪。 - 3.創(chuàng)建一個類用于分析需要的數(shù)據(jù)瞭吃,
prettytable
模塊用于創(chuàng)建圖形化表格碌嘀,colorama
模塊用于給表格上色。
class TransCollection:
header = '車次 車站 時間 歷時 一等座 二等座 軟臥 硬臥 硬座 無座'.split()
def __init__(self, available_trains, options):
self.availavle_trains = available_trains
self.options = options
def _get_duration(self, train_data):
duration = train_data.get('lishi').replace(':', '小時')+'分'
if duration.startswith('00'):
return duration[4:]
if duration.startswith('0'):
return duration[1:]
return duration
@property
def trains(self):
for train in self.availavle_trains:
train_data = train['queryLeftNewDTO']
train_number = train_data['station_train_code'][0].lower() # 開頭轉(zhuǎn)換成小寫
if not self.options or train_number in self.options:
train = [
train_data['station_train_code'], # 車次
'\n'.join([Fore.GREEN+train_data['from_station_name']+Fore.RESET, # 車站
Fore.RED+train_data['to_station_name']+Fore.RESET]),
'\n'.join([Fore.GREEN+train_data['start_time']+Fore.RESET, # 車站
Fore.RED+train_data['arrive_time']+Fore.RESET]),
self._get_duration(train_data), # 歷時
train_data['zy_num'], # 一等座
train_data['ze_num'], # 二等座
train_data['rw_num'], # 軟臥
train_data['yw_num'], # 硬臥
train_data['yz_num'], # 硬座
train_data['wz_num'], # 無座
]
yield train
def pretty_print(self):
pt = PrettyTable()
pt._set_field_names(self.header)
for train in self.trains:
pt.add_row(train)
print(pt)
- 4.創(chuàng)建一個上面類的對象歪架,調(diào)用
pretty_print
函數(shù)股冗,在cli函數(shù)中添加
def cli():
arguments = docopt(__doc__)
from_station = stations.get(arguments['<from>'])
to_staion = stations.get(arguments['<to>'])
date = arguments['<date>']
url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date={}&leftTicketDTO.' \
'from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.\
format(date, from_station, to_staion)
response = requests.get(url, verify=False)
options = ''.join([key for key, value in arguments.items() if value is True])
TransCollection(response.json()['data'], options).pretty_print()