12306火車票查詢--python

    最近我看到看到使用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()

    好了,基本上就結束了,按照開頭的哪樣,就能查詢你想要的車次信息了

相關文章
相關標籤/搜索