zoukankan      html  css  js  c++  java
  • 12306火车票查询--python

        最近我看到看到使用python实现火车票查询,我自己也实现了,感觉收获蛮多的,下面我就把每一步骤都详细给分享出来。(注意使用的是python3)

        首先我将最终结果给展示出来:

        在cmd命令行执行:python tickets.py -dk shanghai chengdu 20161007 > result.txt

    意思是:查询 上海--成都 2016.10.07 的D和K开头的列车信息,并保存到 result.txt文件中;下面就是result.txt文件中的结果:

        下面的将是实现步骤:

      1、安装第三方库 pip install 安装:requests,docopt,prettytable

          2、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 是可以随便写的,不影响解析

    最终打印的结果是一个字典,方便后面使用:

        3、获取列车的信息

    我们在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-05、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查询数据显示出来的格式,

        4、接下来就是整合各个模块: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-05、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()

        好了,基本上就结束了,按照开头的哪样,就能查询你想要的车次信息了

  • 相关阅读:
    使用jsonEditor打造一个复杂json编辑器
    【原创】一次“诡异”的容器Unix Socket通信问题分析
    【原创】Ingress-Nginx-Controller的Metrics监控源码改造简析
    IDEA+DevTools实现热部署功能
    ElementUI按需引入各种组件
    vue-cli4.0更新后怎样将eslint关闭
    Mysql修改字段名、修改字段类型
    博客搬家CSDN
    如何优雅的处理Restful
    java系列之注解
  • 原文地址:https://www.cnblogs.com/xiaoshitoutest/p/5923813.html
Copyright © 2011-2022 走看看