最近我看到看到使用python實現火車票查詢,我本身也實現了,感受收穫蠻多的,下面我就把每一步驟都詳細給分享出來。(注意使用的是python3)python
首先我將最終結果給展現出來:mysql
在cmd命令行執行:python tickets.py -dk shanghai chengdu 20161007 > result.txt正則表達式
意思是:查詢 上海--成都 2016.10.07 的D和K開頭的列車信息,並保存到 result.txt文件中;下面就是result.txt文件中的結果:sql
下面的將是實現步驟:json
一、安裝第三方庫 pip install 安裝:requests,docopt,prettytableapp
二、docopt能夠用來解析從命令行中輸入的參數:函數
""" Usage: test [-gdtkz] <from> <to> <date> Options: -h,--help 顯示幫助菜單 -g 高鐵 -d 動車 -t 特快 -k 快速 -z 直達 Example: tickets -gdt beijing shanghai 2016-08-25 """ import docopt args = docopt.docopt(__doc__) print(args)
# 上面 """ """ 包含中的:
#Usage: # test [-gdtkz] <from> <to> <date>
#是必需要的 test 是能夠隨便寫的,不影響解析
最終打印的結果是一個字典,方便後面使用:url
三、獲取列車的信息spa
咱們在12306的餘票查詢的接口:命令行
url:https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate=2016-10-05&from_station=CDW&to_station=SHH
方法爲:get
傳輸的參數:queryDate:2016-10-0五、from_station:CDW、to_station:SHH
其中城市對應簡稱是須要另外的接口查詢得出
3.1 查詢城市對應的簡稱:
這個接口的url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8968'
方法是get,對返回結果利用正則表達式,取出城市名和簡稱的值(返回的值相似:7@cqn|重慶南|CRW|chongqingnan|cqn|,咱們須要的就是:CRW、chongqingnan),代碼以下parse_stations.py:
1 #coding=utf-8 2 3 import requests 4 import re 5 from pprint import pprint 6 7 8 def get_stations(): 9 # 7@cqn|重慶南|CRW|chongqingnan|cqn| 10 url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8968' 11 r = requests.get(url,verify=False) 12 patter = re.compile('([A-Z]+)\|([a-z]+)') 13 items = dict(re.findall(patter,r.text)) 14 stations = dict(zip(items.values(),items.keys())) 15 # for key in stations: 16 # print("{0}-->{1}".format(key,stations[key])) 17 pprint(stations,indent=4) 18 19 if __name__ == '__main__': 20 get_stations()
其中pprint這個模塊能是打印出來的信息,更加方便閱讀:
在cmd中運行:python parse_stations.py > stations.py
就會在當前目錄下獲得stations.py文件,文件中就是站點名字和簡稱,在stations.py文件中加入"stations = "這樣就是一個字典,方便後面的取值,下面就是stations.py文件的內容:
3.2 如今獲取列車信息的參數已經準備齊了,接下來就是拿到列車的返回值,解析出本身須要的信息,好比:車次號,一等座的票數等等。。,myprettytable.py
#coding=utf-8 from prettytable import PrettyTable class TrainCollection(object): """ 解析列車信息 """ # 顯示車次、出發/到達站、 出發/到達時間、歷時、一等坐、二等坐、軟臥、硬臥、硬座 header = '序號 車次 出發站/到達站 出發時間/到達時間 歷時 商務座 一等座 二等座 軟臥 硬臥 硬座 無座'.split() def __init__(self,rows,traintypes): self.rows = rows self.traintypes = traintypes def _get_duration(self,row): """ 獲取車次運行的時間 """ duration = row.get('lishi').replace(':','小時') + '分' if duration.startswith('00'): return duration[4:] elif duration.startswith('0'): return duration[1:] return duration @property def trains(self): result = [] flag = 0 for row in self.rows: if row['station_train_code'][0] in self.traintypes: flag += 1 train = [ # 序號 flag, # 車次 row['station_train_code'], # 出發、到達站點 '/'.join([row['from_station_name'],row['to_station_name']]), # 成功、到達時間 '/'.join([row['start_time'],row['arrive_time']]), # duration 時間 self._get_duration(row), # 商務座 row['swz_num'], # 一等座 row['zy_num'], # 二等座 row['ze_num'], # 軟臥 row['rw_num'], # 硬臥 row['yw_num'], # 硬座 row['yz_num'], # 無座 row['wz_num'] ] result.append(train) return result def print_pretty(self): """打印列車信息""" pt = PrettyTable() pt._set_field_names(self.header) for train in self.trains: pt.add_row(train) print(pt) if __name__ == '__main__': t = TrainCollection()
prettytable 這個庫是能打印出相似mysql查詢數據顯示出來的格式,
四、接下來就是整合各個模塊:tickets.py
1 """Train tickets query via command-line. 2 3 Usage: 4 tickets [-gdtkz] <from> <to> <date> 5 6 Options: 7 -h,--help 顯示幫助菜單 8 -g 高鐵 9 -d 動車 10 -t 特快 11 -k 快速 12 -z 直達 13 14 Example: 15 tickets -gdt beijing shanghai 2016-08-25 16 """ 17 import requests 18 from docopt import docopt 19 from stations import stations 20 # from pprint import pprint 21 from myprettytable import TrainCollection 22 23 class SelectTrain(object): 24 25 def __init__(self): 26 """ 27 獲取命令行輸入的參數 28 """ 29 self.args = docopt(__doc__)#這個是獲取命令行的全部參數,返回的是一個字典 30 31 32 def cli(self): 33 """command-line interface""" 34 # 獲取 出發站點和目標站點 35 from_station = stations.get(self.args['<from>']) #出發站點 36 to_station = stations.get(self.args['<to>']) # 目的站點 37 leave_time = self._get_leave_time()# 出發時間 38 39 url = 'https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate={0}&from_station={1}&to_station={2}'.format( 40 leave_time,from_station,to_station)# 拼接請求列車信息的Url 41 42 # 獲取列車查詢結果 43 r = requests.get(url,verify=False) 44 traindatas = r.json()['data']['datas'] # 返回的結果,轉化成json格式,取出datas,方便後面解析列車信息用 45 46 # 解析列車信息 47 traintypes = self._get_traintype() 48 views = TrainCollection(traindatas,traintypes) 49 views.print_pretty() 50 51 def _get_traintype(self): 52 """ 53 獲取列車型號,這個函數的做用是的目的是:當你輸入 -g 是隻是返回 高鐵,輸入 -gd 返回動車和高鐵,當不輸參數時,返回全部的列車信息 54 """ 55 traintypes = ['-g','-d','-t','-k','-z'] 56 # result = [] 57 # for traintype in traintypes: 58 # if self.args[traintype]: 59 # result.append(traintype[-1].upper()) 60 61 trains = [traintype[-1].upper() for traintype in traintypes if self.args[traintype]] 62 if trains: 63 return trains 64 else: 65 return ['G','D','T','K','Z'] 66 67 def _get_leave_time(self): 68 """ 69 獲取出發時間,這個函數的做用是爲了:時間能夠輸入兩種格式:2016-10-0五、20161005 70 """ 71 leave_time = self.args['<date>'] 72 if len(leave_time) == 8: 73 return '{0}-{1}-{2}'.format(leave_time[:4],leave_time[4:6],leave_time[6:]) 74 75 if '-' in leave_time: 76 return leave_time 77 78 79 if __name__ == '__main__': 80 cli = SelectTrain() 81 cli.cli()
好了,基本上就結束了,按照開頭的哪樣,就能查詢你想要的車次信息了