12306显示余票数量(返乡之路不容易之12306余票查询并给出备选方案)
12306显示余票数量(返乡之路不容易之12306余票查询并给出备选方案)代码如下:只要输入出发地、目的地和出发时间,便能输出所有车次信息,有的车次能直接买,有的没法直接买,但是给出了备选,只要在备选中选一个就可以买到票回家喽。不对,咱是干啥的呀,鼓捣代码的,这种大量重复的工作交给它来干岂不是快哉,说干就干此处省略一万字。。。终于实现了!!!
马上过年了,在外打工的游子终于要踏上返乡的旅程,尽管疫情严重,但家还是要回的,咱这离家远的一年到头只能回去一两次,想家呀!不说了,打开12306买票吧,我一看,果然没票了,这商务一等座咱也坐不起呀,这可咋整?
买不到直达的,咱要不多花点钱多买几站,或者先买票上车然后补票?
这个想法不错,那我首先得看每一趟车次的所有停靠站,然后再去搜有没有票。拿G3136这趟车来说,首发站是宁波,终点是太原南,那我只要出发站买在宁波到杭州东之间的任一站,终点站买在杭州东和太原南之间的任一站我就可以上车,一想到有办法回家了,心里还有点小激动。
一搜我就懵了,这么多的停靠站,出发站和到达站的排列组合那还不爆炸了?这得把我累死,回个家容易吗?
不对,咱是干啥的呀,鼓捣代码的,这种大量重复的工作交给它来干岂不是快哉,说干就干
此处省略一万字。。。
终于实现了!!!
只要输入出发地、目的地和出发时间,便能输出所有车次信息,有的车次能直接买,有的没法直接买,但是给出了备选,只要在备选中选一个就可以买到票回家喽。
代码如下:
# coding=utf-8
import requests
import urllib.parse as parse
import time
import json
import pretty_errors
import re
from fake_useragent import UserAgent
TRAIN_number = 2
TRAIN = 3
DEPARTURE_STATION = 6
TERMINUS = 7
DEPARTURE_TIME = 8
ARRIVAL_TIME = 9
DURATION = 10
IF_BOOK = 11
DATE = 13
NO_SEAT = 29
HARD_SEAT = 28
SOFT_SEAT = 27
def Citys():
"""
城市缩写
:return:
"""
headers = {'User-Agent': str(UserAgent().random)}
url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9141'
content = requests.get(url=url headers=headers)
content = content.content.decode('utf-8')
content = content[content.find('=') 2:-2]
content_list = content.split('@')
dict_city = {}
for city in content_list:
str_1 = city[city.find('|') 1:]
city_name = str_1[str_1.find('|') 1:str_1.find('|') 4] # 城市简称名
city_name_1 = str_1[:str_1.find('|')] # 城市名
dict_city[city_name_1] = city_name
return dict_city
def Time():
"""
获取当前时间
:return:
"""
list_time = list(time.localtime())
year = str(list_time[0])
month = str(list_time[1])
day = str(list_time[2])
if len(month) == 1:
month = '0' month
if len(day) == 1:
day = '0' day
return year month day
proxy = {'http': '122.226.57.70:8888'}
class Train:
def __init__(self
from_station
to_station
train_date=Time()[0] '-' Time()[1] '-' Time()[2]
):
self.from_station = from_station
self.to_station = to_station
self.train_date = train_date
self.url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.%s&leftTicketDTO.%s&leftTicketDTO.%s&purpose_codes=ADULT'
# self.headers = {
# 'Cookie': 'JSESSIONID=073CAA21150F40AA7F05551F7E1B5F5C; RAIL_DEVICEID=STuBhcdGH45k8StSkJVyk_v6qFnIUDpyzg1O9l7IyMoOPPIEEuBEqcBRuuv0WOKJrV4MdxGi08T0AzwlQ3d4guOQ6LTNlh7emO8TdgWZe2Wp3OuA9WIKYP5Ly-a3o-f5uHGmyX8yleCV0nzQDSL9grkJHRjA4syw; RAIL_EXPIRATION=1642644949013; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; BIGipServerpool_index=804258314.43286.0000; route=6f50b51faa11b987e576cdb301e545c4; BIGipServerotn=384827914.24610.0000'}
self.headers = {'User-Agent': str(UserAgent().random)}
self.session = requests.session()
self.session.get(
'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=杭州东 HGH&ts=太原南 TNV&date=2022-01-19&flag=N N Y'
headers=self.headers proxies=proxy timeout=5)
def station(self train_number):
"""
查找列车起点可买和终点可买
:return:
"""
url = f'https://kyfw.12306.cn/otn/czxx/queryByTrainNo?' \
f'{parse.urlencode({"train_no": train_number})}&' \
f'{parse.urlencode({"from_station_telecode": Citys()[self.from_station]})}&' \
f'{parse.urlencode({"to_station_telecode": Citys()[self.to_station]})}&' \
f'{parse.urlencode({"depart_date": self.train_date})}'
self.headers['User-Agent'] = str(UserAgent().random)
content = self.session.get(url headers=self.headers proxies=proxy timeout=5)
# content = requests.get(url headers=self.headers proxies=proxy timeout=5)
content = content.content.decode('utf-8')
data = json.loads(content)
stations_data = data['data']['data']
stations_data.sort(key=lambda x: x['station_no'])
from_station_idx = int(
list(filter(lambda x: self.from_station in x['station_name'] stations_data))[0]['station_no'])
from_station_buy = [station['station_name'] for station in stations_data[:from_station_idx]]
to_station_buy = [station['station_name'] for station in stations_data[from_station_idx:]]
return from_station_buy to_station_buy
def train(self):
"""
爬取信息
:return:
"""
url = self.url % (parse.urlencode({"train_date": self.train_date})
parse.urlencode({"from_station": Citys()[self.from_station]})
parse.urlencode({"to_station": Citys()[self.to_station]}))
self.headers['User-Agent'] = str(UserAgent().random)
content = self.session.get(url headers=self.headers proxies=proxy timeout=5)
# content = requests.get(url headers=self.headers proxies=proxy timeout=5)
content = content.content.decode('utf-8')
data = json.loads(content)
dict_train = data['data']['result']
dict_map = data['data']['map']
res = []
for train in dict_train:
train_split = train.split('|')
from_station_buy to_station_buy = self.station(train_split[TRAIN_NUMBER])
buy = []
for from_station to_station in [[x y] for x in from_station_buy for y in to_station_buy]:
if train_split[IF_BOOK] == 'N' and self.book_if(from_station to_station train_split[TRAIN]):
buy.append(f'{from_station}-{to_station}')
train_str = [train_split[TRAIN] dict_map[train_split[DEPARTURE_STATION]]
dict_map[train_split[TERMINUS]] train_split[DEPARTURE_TIME]
train_split[ARRIVAL_TIME] train_split[DURATION]
'可以' if train_split[IF_BOOK] == 'Y' else '不可以' ' '.join(buy)]
res.append('| ' ' | '.join(train_str) ' |')
return res
def book_if(self from_station to_station train_number):
"""
查询是否有票
:param from_station:
:param to_station:
:param train_number:
:return:
"""
url = self.url % (parse.urlencode({"train_date": self.train_date})
parse.urlencode({"from_station": Citys()[from_station]})
parse.urlencode({"to_station": Citys()[to_station]}))
self.headers['User-Agent'] = str(UserAgent().random)
content = self.session.get(url headers=self.headers proxies=proxy timeout=5)
# content = requests.get(url headers=self.headers proxies=proxy timeout=5)
content = content.content.decode('utf-8')
data = json.loads(content)
dict_train = data['data']['result']
train = list(filter(lambda x: x.split('|')[TRAIN] == train_number dict_train))
if not train:
return
return True if train[0].split('|')[IF_BOOK] == 'Y' else False
if __name__ == '__main__':
print('--------------------12306信息查询-----------------------')
while True:
from_station = input('请输入出发地:') or '杭州'
if from_station in Citys():
break
while True:
to_station = input('请输入目的地:') or '太原'
if to_station in Citys():
break
pattern = re.compile('\d{4}-\d{2}-\d{2}')
while True:
date = input('请输入出发时间(注意格式:2022-02-01 默认情况下为购票当日):')
if not date or re.match(pattern date):
break
if not date:
date = Time()[0] '-' Time()[1] '-' Time()[2]
train = Train(from_station to_station date)
#
information = train.train()
print('-------------------------------------------------------')
print('-------------------12306查询结果如下---------------------')
print('-------------------------------------------------------')
print('| 车次 | 出发站 | 到达站 | 出发时间 | 到达时间 | 历时 | 直接买 | 备选 |')
for info in information: print(info)
print('-------------------------------------------------------')
这是第一版的实现,目前还只是粗略地给出备选,省去大家手动搜索的时间,还有好多功能没有实现
- 没有备选排名:虽然给出了备选,但哪个备选好一点没有给个排序
- 没有座位信息(商务/一等/二等/硬座/无座):虽然能买,但是不一定能买到适合自己的(便宜的),有点奢侈了
能回家已经很开心了,准备实现第二版...