python第三方库PrettyTable使用实例

一、简介

PrettyTable 是python中的一个第三方库,可用来生成美观的ASCII格式的表格,十分实用。

二、安装

在保证能够通外网的情况下执行命令:pip install PrettyTable安装即可。

三、基本使用实例

import prettytable as pt

#直接创建表
tb = pt.PrettyTable()
#表头字段
tb.field_names = ["City name", "Area", "Population", "Annual Rainfall"]
#按行添加数据
tb.add_row(["Adelaide",1295, 1158259, 600.5])
tb.add_row(["Brisbane",5905, 1857594, 1146.4])
tb.add_row(["Darwin", 112, 120900, 1714.7])
tb.add_row(["Hobart", 1357, 205556,619.5])
print(tb)
输出结果:
+-----------+------+------------+-----------------+
| City name | Area | Population | Annual Rainfall |
+-----------+------+------------+-----------------+
|  Adelaide | 1295 |  1158259   |      600.5      |
|  Brisbane | 5905 |  1857594   |      1146.4     |
|   Darwin  | 112  |   120900   |      1714.7     |
|   Hobart  | 1357 |   205556   |      619.5      |
+-----------+------+------------+-----------------+
#按列添加数据
tb.add_column('index',[1,2,3,4])
print(tb)
+-----------+------+------------+-----------------+-------+
| City name | Area | Population | Annual Rainfall | index |
+-----------+------+------------+-----------------+-------+
|  Adelaide | 1295 |  1158259   |      600.5      |   1   |
|  Brisbane | 5905 |  1857594   |      1146.4     |   2   |
|   Darwin  | 112  |   120900   |      1714.7     |   3   |
|   Hobart  | 1357 |   205556   |      619.5      |   4   |
+-----------+------+------------+-----------------+-------+
#使用不同的输出风格
tb.set_style(pt.MSWORD_FRIENDLY)
print('--- style:MSWORD_FRIENDLY -----')
print(tb)
--- style:MSWORD_FRIENDLY -----
| City name | Area | Population | Annual Rainfall |
|  Adelaide | 1295 |  1158259   |      600.5      |
|  Brisbane | 5905 |  1857594   |      1146.4     |
|   Darwin  | 112  |   120900   |      1714.7     |
|   Hobart  | 1357 |   205556   |      619.5      |

tb.set_style(pt.PLAIN_COLUMNS)
print('--- style:PLAIN_COLUMNS -----')
print(tb)
--- style:PLAIN_COLUMNS -----
City name        Area        Population        Annual Rainfall        
 Adelaide        1295         1158259               600.5             
 Brisbane        5905         1857594               1146.4            
  Darwin         112           120900               1714.7            
  Hobart         1357          205556               619.5       

#随机风格,每次不同
tb.set_style(pt.RANDOM)
print('--- style:MSWORD_FRIENDLY -----')
print(tb)
--- style:MSWORD_FRIENDLY -----
@    Adelaide     1295     1158259     600.5 @
@    Brisbane     5905     1857594     1146.4@
@     Darwin      112       120900     1714.7@
@     Hobart      1357      205556     619.5 @

tb.set_style(pt.DEFAULT)
print('--- style:DEFAULT -----')
print(tb)  
--- style:DEFAULT -----
+-----------+------+------------+-----------------+
| City name | Area | Population | Annual Rainfall |
+-----------+------+------------+-----------------+
|  Adelaide | 1295 |  1158259   |      600.5      |
|  Brisbane | 5905 |  1857594   |      1146.4     |
|   Darwin  | 112  |   120900   |      1714.7     |
|   Hobart  | 1357 |   205556   |      619.5      |
+-----------+------+------------+-----------------+

#不打印,获取表格字符串
s = tb.get_string()
print(s)
+-----------+------+------------+-----------------+
| City name | Area | Population | Annual Rainfall |
+-----------+------+------------+-----------------+
|  Adelaide | 1295 |  1158259   |      600.5      |
|  Brisbane | 5905 |  1857594   |      1146.4     |
|   Darwin  | 112  |   120900   |      1714.7     |
|   Hobart  | 1357 |   205556   |      619.5      |
+-----------+------+------------+-----------------+

## 可以只获取指定列或行
s = tb.get_string(fields=["City name", "Population"],start=1,end=4)
print(s)
+-----------+------------+
| City name | Population |
+-----------+------------+
|  Brisbane |  1857594   |
|   Darwin  |   120900   |
|   Hobart  |   205556   |
+-----------+------------+

# 自定义表格输出样式
#设定左对齐
tb.align = 'l'

#设定数字输出格式
tb.float_format = "2.2"

#设定边框连接符为'*"
tb.junction_char = "*"

#设定排序方式
tb.sortby = "City name"

#设定左侧不填充空白字符
tb.left_padding_width = 0
print(tb)
*----------*-----*-----------*----------------*
|City name |Area |Population |Annual Rainfall |
*----------*-----*-----------*----------------*
|Adelaide  |1295 |1158259    |600.50          |
|Brisbane  |5905 |1857594    |1146.40         |
|Darwin    |112  |120900     |1714.70         |
|Hobart    |1357 |205556     |619.50          |
*----------*-----*-----------*----------------*
#不显示边框
tb.border = 0
print(tb)
City name Area Population Annual Rainfall 
Adelaide  1295 1158259    600.50          
Brisbane  5905 1857594    1146.40         
Darwin    112  120900     1714.70         
Hobart    1357 205556     619.50        

#修改边框分隔符
tb.set_style(pt.DEFAULT)
tb.horizontal_char = '+'
print(tb)
+++++++++++++++++++++++++++++++++++++++++++++++++++
| City name | Area | Population | Annual Rainfall |
+++++++++++++++++++++++++++++++++++++++++++++++++++
| Adelaide  | 1295 | 1158259    | 600.50          |
| Brisbane  | 5905 | 1857594    | 1146.40         |
| Darwin    | 112  | 120900     | 1714.70         |
| Hobart    | 1357 | 205556     | 619.50          |
+++++++++++++++++++++++++++++++++++++++++++++++++++
#prettytable也支持输出HTML代码
s = tb.get_html_string()
print(s)

<table>
    <tr>
        <th>City name</th>
        <th>Area</th>
        <th>Population</th>
        <th>Annual Rainfall</th>
    </tr>
    <tr>
        <td>Adelaide</td>
        <td>1295</td>
        <td>1158259</td>
        <td>600.50</td>
    </tr>
    <tr>
        <td>Brisbane</td>
        <td>5905</td>
        <td>1857594</td>
        <td>1146.40</td>
    </tr>
    <tr>
        <td>Darwin</td>
        <td>112</td>
        <td>120900</td>
        <td>1714.70</td>
    </tr>
    <tr>
        <td>Hobart</td>
        <td>1357</td>
        <td>205556</td>
        <td>619.50</td>
    </tr>
</table>

#使用copy方法复制对象
#tb.set_style(pt.DEFAULT)
tb.horizontal_char = '.'
tb2 = tb.copy()
tb.align  = 'l'
tb2.align = 'r'
print(tb)
print(tb2)
+...........+......+............+.................+
| City name | Area | Population | Annual Rainfall |
+...........+......+............+.................+
| Adelaide  | 1295 | 1158259    | 600.50          |
| Brisbane  | 5905 | 1857594    | 1146.40         |
| Darwin    | 112  | 120900     | 1714.70         |
| Hobart    | 1357 | 205556     | 619.50          |
+...........+......+............+.................+
+...........+......+............+.................+
| City name | Area | Population | Annual Rainfall |
+...........+......+............+.................+
|  Adelaide | 1295 |    1158259 |          600.50 |
|  Brisbane | 5905 |    1857594 |         1146.40 |
|    Darwin |  112 |     120900 |         1714.70 |
|    Hobart | 1357 |     205556 |          619.50 |
+...........+......+............+.................+

#直接赋值,得到的是索引
tb.horizontal_char = '-'
tb.aliign = 'l'
tb3 = tb
tb3.align = 'r'
print(tb)
print(tb3)
+-----------+------+------------+-----------------+
| City name | Area | Population | Annual Rainfall |
+-----------+------+------------+-----------------+
|  Adelaide | 1295 |    1158259 |          600.50 |
|  Brisbane | 5905 |    1857594 |         1146.40 |
|    Darwin |  112 |     120900 |         1714.70 |
|    Hobart | 1357 |     205556 |          619.50 |
+-----------+------+------------+-----------------+
+-----------+------+------------+-----------------+
| City name | Area | Population | Annual Rainfall |
+-----------+------+------------+-----------------+
|  Adelaide | 1295 |    1158259 |          600.50 |
|  Brisbane | 5905 |    1857594 |         1146.40 |
|    Darwin |  112 |     120900 |         1714.70 |
|    Hobart | 1357 |     205556 |          619.50 |
+-----------+------+------------+-----------------+

四、查询12306余票信息

首先我们来看看每查询一条信息12306网站返回的信息:

请求链接:

https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2018-01-31&leftTicketDTO.from_station=XAY&leftTicketDTO.to_station=GZG&purpose_codes=ADULT

很显然我们只需要关注三个参数:train_date,from_station,to_station

 #获得result
1
import requests 2 import urllib 3 import json 5 """获取data""" 6 def getData(url): 7 data = '' 8 while 1: 9 try: 10 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} 11 12 # 关键代码:############################################### 13 14 req = urllib.request.Request(url=url, headers=headers) 15 16 data = urllib.request.urlopen(req).read().decode('utf-8') 17 18 ########################################################### 19 if data.startswith(u'\ufeff'): 20 data = data.encode('utf8')[3:].decode('utf-8') 21 break 22 except: 23 continue 24 return data 25 26 """获取result""" 27 28 def resolveData(): 29 #查询链接 30 url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2018-01-31&leftTicketDTO.from_station=XAY&leftTicketDTO.to_station=GZG&purpose_codes=ADULT' 31 32 #获取数据 33 while 1: 34 try: 35 data = getData(url) 36 lists = json.loads(data)["data"]["result"] 37 break 38 except: 39 continue#获取失败则重新获取 40 for item in lists:#打印result信息 41 print(item)

调用resolveData():

观察这一长串字符我们还是能发现规律的,所有的信息都以"|"为分割线,图中已经显示了一些信息,其他信息需要我们观察多个result结果才能找出对应位置。

解析result信息:

  1 """获取result"""
  2 
  3 def resolveData():
  4 
  5     #查询链接
  6 
  7     url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2018-01-31&leftTicketDTO.from_station=XAY&leftTicketDTO.to_station=GZG&purpose_codes=ADULT'    #获取数据
  8 
  9     while 1:
 10 
 11         try:
 12 
 13             data = getData(url)
 14 
 15             lists = json.loads(data)["data"]["result"]
 16 
 17             break
 18 
 19         except:
 20 
 21             continue
 22 
 23     cont = []
 24 
 25     name = [
 26 
 27         "station_train_code",
 28 
 29         "from_station_name",
 30 
 31         'start_time',
 32 
 33         "lishi",
 34 
 35         "swz_num",
 36 
 37         "zy_num",
 38 
 39         "ze_num",
 40 
 41         "gr_num",
 42 
 43         "rw_num",
 44 
 45 "dw_num",
 46 
 47         "yw_num",
 48 
 49         "rz_num",
 50 
 51         "yz_num",
 52 
 53         "wz_num",
 54 
 55         "qt_num",
 56 
 57         "note_num"
 58 
 59     ]
 60 
 61  
 62 
 63     for items in lists:#遍历result的每一项
 64 
 65         #data字典用于存放每一车次的余票信息
 66 
 67         data = {
 68 
 69             "station_train_code": '',
 70 
 71             "from_station_name": '',
 72 
 73             "to_station_name": '',
 74 
 75             'start_time': '',
 76 
 77             'end': '',
 78 
 79             "lishi": '',
 80 
 81             "swz_num": '',
 82 
 83             "zy_num": '',
 84 
 85             "ze_num": '',
 86 
 87             "dw_num": '',
 88 
 89             "gr_num": '',
 90 
 91             "rw_num": '',
 92 
 93             "yw_num": '',
 94 
 95             "rz_num": '',
 96 
 97             "yz_num": '',
 98 
 99             "wz_num": '',
100 
101             "qt_num": '',
102 
103             "note_num": ''
104 
105         }
106 
107         item = items.split('|')#用"|"进行分割
108 
109         data['station_train_code'] = item[3]#车次在3号位置
110 
111         data['from_station_name'] = item[6]#始发站信息在6号位置
112 
113         data['to_station_name'] = item[7]#终点站信息在7号位置
114 
115         data['start_time'] = item[8]#出发时间信息在8号位置
116 
117         data['arrive_time'] = item[9]#抵达时间在9号位置
118 
119         data['lishi'] = item[10]#经历时间在10号位置
120 
121         data['swz_num'] = item[32] or item[25]# 特别注意:商务座在32或25位置
122 
123         data['zy_num'] = item[31]#一等座信息在31号位置
124 
125         data['ze_num'] = item[30]#二等座信息在30号位置
126 
127         data['gr_num'] = item[21]#高级软卧信息在31号位置
128 
129         data['rw_num'] = item[23]#软卧信息在23号位置
130 
131         data['dw_num'] = item[27]#动卧信息在27号位置
132 
133         data['yw_num'] = item[28]#硬卧信息在28号位置
134 
135         data['rz_num'] = item[24]#软座信息在24号位置
136 
137         data['yz_num'] = item[29]#硬座信息在29号位置
138 
139         data['wz_num'] = item[26]#无座信息在26号位置
140 
141         data['qt_num'] = item[22]#其他信息在22号位置
142 
143         data['note_num'] = item[1]#备注在1号位置
144 
145        
146 
147        #如果没有信息则用“-”代替
148 
149         for pos in name:
150 
151             if data[pos] == '':
152 
153                 data[pos] = '-'
154 
155  
156 
157         cont.append(data)
158 
159     tickets = []#存放所有车次的余票信息
160 
161     #格式化添加进tickets中
162 
163     for x in cont:
164 
165         tmp = []
166 
167         for y in name:
168 
169             if y == "from_station_name":
170 
171                 s = stations2CN[x[y]] + '--' + stations2CN[x["to_station_name"]]
172 
173                 tmp.append(s)
174 
175             elif y == "start_time":
176 
177                 s = x[y] + '--' + x["arrive_time"]
178 
179                 tmp.append(s)
180 
181             elif y == "station_train_code":
182 
183                 s = x[y]
184 
185                 tmp.append(s)
186 
187             else:
188 
189                 tmp.append(x[y])
190 
191         tickets.append(tmp)
192 
193     return tickets#返回所有车次余票信息
194 
195  
196 
197 if __name__ == "__main__":#main方法
198 
199     tickets = resolveData()
200 
201     for ticket in tickets:
202 
203         print(ticket)

同12306官网进行对比,查询解析准确。搞定!

下一步我们将使数据输出的更加漂亮。

 1 #打印车票函数:
 2 from prettytable import PrettyTable
 3 #显示查询结果
 4 def display(tickets):
 5     ptable = PrettyTable('车次 出发/到达站 出发/到达时间 历时 商务座 一等座 二等座 高级软卧 软卧 动卧 硬卧 软座 硬座 无座 其他 备注'.split(' '))
 6     for ticket in tickets:
 7         ptable.add_row(ticket)
 8     print(ptable)
 9 
10 if __name__ == "__main__":#main方法
11     tickets = resolveData()
12     display(tickets)
13     input('按任意键退出...')

使用了prettytable后使输出十分规整,现在我想为这一表格中的字体加上颜色,我们需要使用colorama。 

环境安装:pip install colorama

创建一个专门用于更改颜色的类Colored并且添加相应方法:

 1 from colorama import init, Fore, Back, Style
 2 
 3 init(autoreset=False)
 4 class Colored(object):
 5     #  前景色:红色  背景色:默认
 6     def red(self, s):
 7         return Fore.LIGHTRED_EX + s + Fore.RESET
 8     #  前景色:绿色  背景色:默认
 9     def green(self, s):
10         return Fore.LIGHTGREEN_EX + s + Fore.RESET
11     def yellow(self, s):
12         return Fore.LIGHTYELLOW_EX + s + Fore.RESET
13     def white(self,s):
14         return Fore.LIGHTWHITE_EX + s + Fore.RESET
15     def blue(self,s):
16         return Fore.LIGHTBLUE_EX + s + Fore.RESET

现在我们使用这个类,修改resolveData()函数的部分代码:

def resolveData():
    #查询链接
    url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2018-01-31&leftTicketDTO.from_station=XAY&leftTicketDTO.to_station=GZG&purpose_codes=ADULT'    #获取数据
    while 1:
        try:
            data = getData(url)
            lists = json.loads(data)["data"]["result"]
            break
        except:
            continue
    cont = []
    name = [
        "station_train_code",
        "from_station_name",
        'start_time',
        "lishi",
        "swz_num",
        "zy_num",
        "ze_num",
        "gr_num",
        "rw_num",
        "dw_num",
        "yw_num",
        "rz_num",
        "yz_num",
        "wz_num",
        "qt_num",
        "note_num"
    ]
    color = Colored()#创建Colored对象
    for items in lists:#遍历result的每一项
        #data字典用于存放每一车次的余票信息
        data = {
            "station_train_code": '',
            "from_station_name": '',
            "to_station_name": '',
            'start_time': '',
            'end': '',
            "lishi": '',
            "swz_num": '',
            "zy_num": '',
            "ze_num": '',
            "dw_num": '',
            "gr_num": '',
            "rw_num": '',
            "yw_num": '',
            "rz_num": '',
            "yz_num": '',
            "wz_num": '',
            "qt_num": '',
            "note_num": ''
        }
        item = items.split('|')#用"|"进行分割
        data['station_train_code'] = item[3]#车次在3号位置
        data['from_station_name'] = item[6]#始发站信息在6号位置
        data['to_station_name'] = item[7]#终点站信息在7号位置
        data['start_time'] = item[8]#出发时间信息在8号位置
        data['arrive_time'] = item[9]#抵达时间在9号位置
        data['lishi'] = item[10]#经历时间在10号位置
        data['swz_num'] = item[32] or item[25]# 特别注意:商务座在32或25位置
        data['zy_num'] = item[31]#一等座信息在31号位置
        data['ze_num'] = item[30]#二等座信息在30号位置
        data['gr_num'] = item[21]#高级软卧信息在31号位置
        data['rw_num'] = item[23]#软卧信息在23号位置
        data['dw_num'] = item[27]#动卧信息在27号位置
        data['yw_num'] = item[28]#硬卧信息在28号位置
        data['rz_num'] = item[24]#软座信息在24号位置
        data['yz_num'] = item[29]#硬座信息在29号位置
        data['wz_num'] = item[26]#无座信息在26号位置
        data['qt_num'] = item[22]#其他信息在22号位置
        if item[0] == 'null':
            data['note_num'] = item[1]
        else:
            data['note_num'] = color.white(item[1])#加高亮白色
            #如果没有信息则用“-”代替
        for pos in name:
            if data[pos] == '':
                data[pos] = '-'

        cont.append(data)
    tickets = []#存放所有车次的余票信息
    #格式化添加进tickets中
    for x in cont:
        tmp = []
        for y in name:
            if y == "from_station_name":
                s = color.green(stations2CN[x[y]]) + '\n' + color.red(stations2CN[x["to_station_name"]])#始发站绿色,终点站红色
                tmp.append(s)
            elif y == "start_time":
                s = color.green(x[y]) + '\n' + color.red(x["arrive_time"])
                tmp.append(s)
            elif y == "station_train_code":
                s = color.yellow(x[y])
                tmp.append(s)
            else:
                tmp.append(x[y])
        tickets.append(tmp)
    return tickets#返回所有车次余票信息

         我们能实现很漂亮的输出了,可是只是固定时间固定车站之间的车票信息,在本次中我们使用docopt来实现命令行的参数输入,从而查询任意时间任意两个车站的余票。 

环境安装:pip install docopt

使用docopt实现命令行的输入:

 1 """Train tickets query via command-line.
 2 Usage:
 3     tickets <from> <to> <date>
 4 
 5 Options:
 6     -h,--help        显示帮助菜单
 7     from             出发车站
 8     to               终点站
 9     date             出发日期
10 
11 Example:
12     filename 南京 北京 2016-07-01
13 """
14 from docopt import docopt
15 
16 def cli():
17     """command-line interface"""
18     arguments = docopt(__doc__)

在main函数中调用cli()方法并打印arguments: 
这里写图片描述 
成功的通过命令行传递查询参数。

接下来我们只需要稍微修改一下resolveData函数就行了。 
修改两行:

1 def resolveData(from_station,to_station,from_date):
2     #查询链接
3     url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(from_date, stations2CODE[from_station],stations2CODE[to_station])    #获取数据

stations2CODE将输入的车站名转换成12306规定的代码。这是一个字典,具体在stationInfo.py中。

在cli()函数中调用修改后的resolveData方法并打印表格:

1 def cli():
2 """command-line interface"""
3 arguments = docopt(__doc__)
4 tickets = resolveData(arguments['<from>'], arguments['<to>'], arguments['<date>'])
5 display(tickets)

添加票价信息:

票价的查询根据前面result的解析是无法获取的,票价需要另外发送请求获取。

请求链接: 
https://kyfw.12306.cn/otn/leftTicket/queryTicketPrice?train_no=88000K131008&from_station_no=12&to_station_no=27&seat_types=1413&train_date=2018-01-30 
关注train_no、from_station_no、to_station_no、seat_types、train_date这几个参数。

有了前面教程解析车票信息result的基础解析车票也是大同小异罢了,找出对应车票类型对应的票价对应的位置就行。

实现获取车票票价的函数:

 1 #pricesDic用于存放票价信息
 2 pricesDic = {
 3 'A': '',
 4 'B': '',
 5 'C': '',
 6 'D': '',
 7 'E': '',
 8 'F': '',
 9 'G': '',
10 'H': '',
11 'I': '',
12 'J': ''
13 }
14 
15 def getPrice(threadname,train_no, from_station_no, to_station_no, seat_types, date,pricesDic):
16 while 1:
17 try:
18 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}
19 moneyUrl = "https://kyfw.12306.cn/otn/leftTicket/queryTicketPrice?train_no={}&from_station_no={}&to_station_no={}&seat_types={}&train_date={}".format(
20 train_no, from_station_no, to_station_no, seat_types, date)
21 req = urllib.request.Request(url=moneyUrl, headers=headers)
22 r_price = urllib.request.urlopen(req).read().decode('utf-8')
23 if r_price.startswith(u'\ufeff'):
24 r_price = r_price.encode('utf8')[3:].decode('utf-8')
25 # print(r_price)
26 r_price = json.loads(r_price)
27 break
28 except:
29 continue
30 price = r_price['data']
31 price = dict(price)#获取data字典,票价信息在字典中
32 A = ('A9' in price.keys())#商务座票价对应key是A9或者P
33 if A == False:
34 A = ('P' in price.keys())
35 if A == False:
36 A = ''
37 else:
38 A = price['P']
39 else:
40 A = price['A9']
41 
42 B = ('M' in price.keys())#一等座对应key为M
43 if B == False:
44 B = ''
45 else:
46 B = price['M']
47 C = ('O' in price.keys())#二等座对应key为O
48 if C == False:
49 C = ''
50 else:
51 C = price['O']
52 D = ('A6' in price.keys())
53 if D == False:
54 D = ''
55 else:
56 D = price['A6']
57 E = ('A4' in price.keys())
58 if E == False:
59 E = ''
60 else:
61 E = price['A4']
62 F = ('F' in price.keys())
63 if F == False:
64 F = ''
65 else:
66 F = price['F']
67 G = ('A3' in price.keys())
68 if G == False:
69 G = ''
70 else:
71 G = price['A3']
72 
73 H = ('A2' in price.keys())
74 if H == False:
75 H = ''
76 else:
77 H = price['A2']
78 I = ('A1' in price.keys())
79 if I == False:
80 I = ''
81 else:
82 I = price['A1']
83 
84 J = ('WZ' in price.keys())
85 if J == False:
86 J = ''
87 else:
88 J = price['WZ']
89 pricesDic['A'] = A
90 pricesDic['B'] = B
91 pricesDic['C'] = C
92 pricesDic['D'] = D
93 pricesDic['E'] = E
94 pricesDic['F'] = F
95 pricesDic['G'] = G
96 pricesDic['H'] = H
97 pricesDic['I'] = I
98 pricesDic['J'] = J

我实现查询票价使用了Python中的线程,另外开启一个线程去查询票价:

 1 import threading
 2 
 3 threadLock = threading.Lock()
 4 class myThread (threading.Thread):
 5 def __init__(self, threadID, threadName, train_no, from_station_no, to_station_no, seat_types, date,pricesDic):
 6 threading.Thread.__init__(self)
 7 self.threadID = threadID
 8 self.threadName = threadName
 9 self.train_no = train_no
10 self.from_station_no = from_station_no
11 self.to_station_no = to_station_no
12 self.seat_types = seat_types
13 self.date = date
14 self.pricesDic = pricesDic
15 def run(self):
16 #print ("开始线程:" + self.threadName)
17 # 获取锁,用于线程同步
18 threadLock.acquire()
19 getPrice(self.threadName, self.train_no, self.from_station_no, self.to_station_no, self.seat_types, self.date, self.pricesDic)
20 # 释放锁,开启下一个线程
21 threadLock.release()
22 #print ("退出线程:" + self.threadName)

在resolveData函数中开启线程查询票价,并且将票价加入余票信息中:
再次修改resolveData函数,观察变化:

  1 def resolveData(from_station, to_station, date):
  2 #拼接出查询链接
  3 url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(date, stations2CODE[from_station], stations2CODE[to_station])
  4 #获取数据
  5 while 1:
  6 try:
  7 data = getData(url)
  8 lists = json.loads(data)["data"]["result"]
  9 # if data['status'] == False:
 10 # print('获取失败!请检查网络')
 11 # break
 12 break
 13 except:
 14 continue
 15 cont = []
 16 name = [
 17 "station_train_code",
 18 "from_station_name",
 19 'start_time',
 20 "lishi",
 21 "swz_num",
 22 "zy_num",
 23 "ze_num",
 24 "gr_num",
 25 "rw_num",
 26 "dw_num",
 27 "yw_num",
 28 "rz_num",
 29 "yz_num",
 30 "wz_num",
 31 "qt_num",
 32 "note_num"
 33 ]
 34 color = Colored()
 35 for items in lists:
 36 data = {
 37 "station_train_code": '',
 38 "from_station_name": '',
 39 "to_station_name": '',
 40 'start_time': '',
 41 'end': '',
 42 "lishi": '',
 43 "swz_num": '',
 44 "zy_num": '',
 45 "ze_num": '',
 46 "dw_num": '',
 47 "gr_num": '',
 48 "rw_num": '',
 49 "yw_num": '',
 50 "rz_num": '',
 51 "yz_num": '',
 52 "wz_num": '',
 53 "qt_num": '',
 54 "note_num": ''
 55 }
 56 item = items.split('|')
 57 data['station_train_code'] = item[3]
 58 data['from_station_name'] = item[6]
 59 data['to_station_name'] = item[7]
 60 data['start_time'] = item[8]
 61 data['arrive_time'] = item[9]
 62 data['lishi'] = item[10]
 63 data['swz_num'] = item[32] or item[25]# 商务座在32或25位置
 64 data['zy_num'] = item[31]
 65 data['ze_num'] = item[30]
 66 data['gr_num'] = item[21]
 67 data['rw_num'] = item[23]
 68 data['dw_num'] = item[27]
 69 data['yw_num'] = item[28]
 70 data['rz_num'] = item[24]
 71 data['yz_num'] = item[29]
 72 data['wz_num'] = item[26]
 73 data['qt_num'] = item[22]
 74 if item[0] == 'null':
 75 data['note_num'] = item[1]
 76 else:
 77 data['note_num'] = color.white(item[1])
 78 #解析出查询票价需要的参数
 79 train_no = item[2]
 80 from_station_no = item[16]
 81 to_station_no = item[17]
 82 types = item[35]
 83 getPriceThread = myThread(1, "Thread-1", train_no, from_station_no, to_station_no, types, date, pricesDic)
 84 getPriceThread.start()#开启查询车票的线程
 85 for pos in name:
 86 if data[pos] == '':
 87 data[pos] = '-'
 88 threadLock.acquire()#必须加锁,这是为了线程同步
 89 for pos in priceName:#将票价添加进余票信息中
 90 if pos == 'swz_num':
 91 data['swz_num'] = data['swz_num'] +'\n'+ color.blue(pricesDic['A'])
 92 if pos == 'zy_num':
 93 data['zy_num'] = data['zy_num'] +'\n'+ color.blue(pricesDic['B'])
 94 if pos == 'ze_num':
 95 data['ze_num'] = data['ze_num'] +'\n'+ color.blue(pricesDic['C'])
 96 if pos == 'gr_num':
 97 data['gr_num'] = data['gr_num'] +'\n'+ color.blue(pricesDic['D'])
 98 if pos == 'rw_num':
 99 data['rw_num'] = data['rw_num'] +'\n'+ color.blue(pricesDic['E'])
100 if pos == 'dw_num':
101 data['dw_num'] = data['dw_num'] +'\n'+ color.blue(pricesDic['F'])
102 if pos == 'yw_num':
103 data['yw_num'] = data['yw_num'] +'\n'+ color.blue(pricesDic['G'])
104 if pos == 'rz_num':
105 data['rz_num'] = data['rz_num'] +'\n'+ color.blue(pricesDic['H'])
106 if pos == 'yz_num':
107 data['yz_num'] = data['yz_num'] +'\n'+ color.blue(pricesDic['I'])
108 if pos == 'wz_num':
109 data['wz_num'] = data['wz_num'] +'\n'+ color.blue(pricesDic['J'])
110 threadLock.release()
111 cont.append(data)
112 color = Colored()
113 tickets = []
114 for x in cont:
115 tmp = []
116 for y in name:
117 if y == "from_station_name":
118 s = color.green(stations2CN[x[y]]) + '\n' + color.red(stations2CN[x["to_station_name"]])
119 tmp.append(s)
120 elif y == "start_time":
121 s = color.green(x[y]) + '\n' + color.red(x["arrive_time"])
122 tmp.append(s)
123 elif y == "station_train_code":
124 s = color.yellow(x[y])
125 tmp.append(s)
126 else:
127 tmp.append(x[y])
128 tickets.append(tmp)
129 return tickets#返回所有车次余票信息


最终测试:

成功获取票价!

到这来为止我们就结束了DOS界面的开发。源代码:
链接:https://pan.baidu.com/s/1c1Gdxra 密码:6xpz

我在此基础上实现了连续多天的查询,并且实现了列车类型的过滤,
源代码在此:链接:https://pan.baidu.com/s/1jI2Ak4Y 密码:02gu


转载原文:https://blog.csdn.net/qq_25343557/article/details/78965044



猜你喜欢

转载自www.cnblogs.com/jason89/p/10223606.html