(五)Python查询12306余票:添加票价信息
程序员文章站
2024-03-17 21:38:34
...
前一篇–>docopt实现参数的输入—–查询任意时间任意车站余票
票价的查询根据前面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的基础解析车票也是大同小异罢了,找出对应车票类型对应的票价对应的位置就行。
实现获取车票票价的函数:
#pricesDic用于存放票价信息
pricesDic = {
'A': '',
'B': '',
'C': '',
'D': '',
'E': '',
'F': '',
'G': '',
'H': '',
'I': '',
'J': ''
}
def getPrice(threadname,train_no, from_station_no, to_station_no, seat_types, date,pricesDic):
while 1:
try:
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}
moneyUrl = "https://kyfw.12306.cn/otn/leftTicket/queryTicketPrice?train_no={}&from_station_no={}&to_station_no={}&seat_types={}&train_date={}".format(
train_no, from_station_no, to_station_no, seat_types, date)
req = urllib.request.Request(url=moneyUrl, headers=headers)
r_price = urllib.request.urlopen(req).read().decode('utf-8')
if r_price.startswith(u'\ufeff'):
r_price = r_price.encode('utf8')[3:].decode('utf-8')
# print(r_price)
r_price = json.loads(r_price)
break
except:
continue
price = r_price['data']
price = dict(price)#获取data字典,票价信息在字典中
A = ('A9' in price.keys())#商务座票价对应key是A9或者P
if A == False:
A = ('P' in price.keys())
if A == False:
A = ''
else:
A = price['P']
else:
A = price['A9']
B = ('M' in price.keys())#一等座对应key为M
if B == False:
B = ''
else:
B = price['M']
C = ('O' in price.keys())#二等座对应key为O
if C == False:
C = ''
else:
C = price['O']
D = ('A6' in price.keys())
if D == False:
D = ''
else:
D = price['A6']
E = ('A4' in price.keys())
if E == False:
E = ''
else:
E = price['A4']
F = ('F' in price.keys())
if F == False:
F = ''
else:
F = price['F']
G = ('A3' in price.keys())
if G == False:
G = ''
else:
G = price['A3']
H = ('A2' in price.keys())
if H == False:
H = ''
else:
H = price['A2']
I = ('A1' in price.keys())
if I == False:
I = ''
else:
I = price['A1']
J = ('WZ' in price.keys())
if J == False:
J = ''
else:
J = price['WZ']
pricesDic['A'] = A
pricesDic['B'] = B
pricesDic['C'] = C
pricesDic['D'] = D
pricesDic['E'] = E
pricesDic['F'] = F
pricesDic['G'] = G
pricesDic['H'] = H
pricesDic['I'] = I
pricesDic['J'] = J
我实现查询票价使用了Python中的线程,另外开启一个线程去查询票价:
import threading
threadLock = threading.Lock()
class myThread (threading.Thread):
def __init__(self, threadID, threadName, train_no, from_station_no, to_station_no, seat_types, date,pricesDic):
threading.Thread.__init__(self)
self.threadID = threadID
self.threadName = threadName
self.train_no = train_no
self.from_station_no = from_station_no
self.to_station_no = to_station_no
self.seat_types = seat_types
self.date = date
self.pricesDic = pricesDic
def run(self):
#print ("开始线程:" + self.threadName)
# 获取锁,用于线程同步
threadLock.acquire()
getPrice(self.threadName, self.train_no, self.from_station_no, self.to_station_no, self.seat_types, self.date, self.pricesDic)
# 释放锁,开启下一个线程
threadLock.release()
#print ("退出线程:" + self.threadName)
在resolveData函数中开启线程查询票价,并且将票价加入余票信息中:
再次修改resolveData函数,观察变化:
def resolveData(from_station, to_station, date):
#拼接出查询链接
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])
#获取数据
while 1:
try:
data = getData(url)
lists = json.loads(data)["data"]["result"]
# if data['status'] == False:
# print('获取失败!请检查网络')
# break
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()
for items in lists:
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]
data['from_station_name'] = item[6]
data['to_station_name'] = item[7]
data['start_time'] = item[8]
data['arrive_time'] = item[9]
data['lishi'] = item[10]
data['swz_num'] = item[32] or item[25]# 商务座在32或25位置
data['zy_num'] = item[31]
data['ze_num'] = item[30]
data['gr_num'] = item[21]
data['rw_num'] = item[23]
data['dw_num'] = item[27]
data['yw_num'] = item[28]
data['rz_num'] = item[24]
data['yz_num'] = item[29]
data['wz_num'] = item[26]
data['qt_num'] = item[22]
if item[0] == 'null':
data['note_num'] = item[1]
else:
data['note_num'] = color.white(item[1])
#解析出查询票价需要的参数
train_no = item[2]
from_station_no = item[16]
to_station_no = item[17]
types = item[35]
getPriceThread = myThread(1, "Thread-1", train_no, from_station_no, to_station_no, types, date, pricesDic)
getPriceThread.start()#开启查询车票的线程
for pos in name:
if data[pos] == '':
data[pos] = '-'
threadLock.acquire()#必须加锁,这是为了线程同步
for pos in priceName:#将票价添加进余票信息中
if pos == 'swz_num':
data['swz_num'] = data['swz_num'] +'\n'+ color.blue(pricesDic['A'])
if pos == 'zy_num':
data['zy_num'] = data['zy_num'] +'\n'+ color.blue(pricesDic['B'])
if pos == 'ze_num':
data['ze_num'] = data['ze_num'] +'\n'+ color.blue(pricesDic['C'])
if pos == 'gr_num':
data['gr_num'] = data['gr_num'] +'\n'+ color.blue(pricesDic['D'])
if pos == 'rw_num':
data['rw_num'] = data['rw_num'] +'\n'+ color.blue(pricesDic['E'])
if pos == 'dw_num':
data['dw_num'] = data['dw_num'] +'\n'+ color.blue(pricesDic['F'])
if pos == 'yw_num':
data['yw_num'] = data['yw_num'] +'\n'+ color.blue(pricesDic['G'])
if pos == 'rz_num':
data['rz_num'] = data['rz_num'] +'\n'+ color.blue(pricesDic['H'])
if pos == 'yz_num':
data['yz_num'] = data['yz_num'] +'\n'+ color.blue(pricesDic['I'])
if pos == 'wz_num':
data['wz_num'] = data['wz_num'] +'\n'+ color.blue(pricesDic['J'])
threadLock.release()
cont.append(data)
color = Colored()
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#返回所有车次余票信息
最终测试:
成功获取票价!
到这来为止我们就结束了DOS界面的开发。源代码:
链接:https://pan.baidu.com/s/1c1Gdxra 密码:6xpz
我在此基础上实现了连续多天的查询,并且实现了列车类型的过滤,
源代码在此:链接:https://pan.baidu.com/s/1jI2Ak4Y 密码:02gu
不懂得地方欢迎交流。
代码有BUG看看能不能您解决
上一篇: CSP 202006-2 稀疏向量