|
|
import tkinter as tk #创建图形用户界面的库
|
|
|
from tkinter import ttk #提供一些更为现代的组件
|
|
|
from tkinter import messagebox #提供一个用于显示消息框的简单接口
|
|
|
import requests #用于进行http请求来获取请12306网站数据
|
|
|
import prettytable as pt#用来创建漂亮的文本表格
|
|
|
import json#处理JSON数据来获取城市车站信息
|
|
|
import datetime#处理日期和时间
|
|
|
|
|
|
# 验证用户输入的城市名称和日期是否有效
|
|
|
def validate_inputs(from_city, to_city, date):
|
|
|
"""验证用户输入的城市名称和日期是否有效"""
|
|
|
# 检查城市名称是否为非空字符串
|
|
|
if not from_city or not to_city:
|
|
|
messagebox.showerror("错误", "城市名称不能为空。")
|
|
|
return False
|
|
|
|
|
|
# 检查日期是否为有效的YYYY-MM-DD格式
|
|
|
if not is_valid_date(date):
|
|
|
messagebox.showerror("错误", "日期格式错误,应为 YYYY-MM-DD。")
|
|
|
return False
|
|
|
|
|
|
return True
|
|
|
|
|
|
def is_valid_date(date_str):
|
|
|
"""检查日期字符串是否为有效的YYYY-MM-DD格式"""
|
|
|
try:
|
|
|
# 尝试将字符串转换为日期
|
|
|
datetime.datetime.strptime(date_str, '%Y-%m-%d')
|
|
|
return True
|
|
|
except ValueError:
|
|
|
return False
|
|
|
|
|
|
# 根据用户输入的出发城市、目的城市和日期来搜索列车
|
|
|
def search_trains():
|
|
|
from_city = from_city_combobox.get()
|
|
|
to_city = to_city_combobox.get()
|
|
|
date = date_entry.get()
|
|
|
train_type = train_type_combobox.get()
|
|
|
|
|
|
# 验证输入:用户输入的出发城市、目的城市和日期无效,则停止执行 search_trains 函数,并返回 None。
|
|
|
if not validate_inputs(from_city, to_city, date):
|
|
|
return
|
|
|
|
|
|
# 读取城市文件 -> 返回json字符串
|
|
|
try:
|
|
|
with open('city.json', 'r', encoding='utf-8') as f:
|
|
|
city_data = json.load(f)
|
|
|
except FileNotFoundError:
|
|
|
messagebox.showerror("错误", "城市数据文件不存在,请确保 city.json 文件在当前目录下。")
|
|
|
return
|
|
|
except json.JSONDecodeError:
|
|
|
messagebox.showerror("错误", "城市数据文件格式错误,请确保 city.json 文件内容为有效的 JSON 格式。")
|
|
|
return
|
|
|
|
|
|
# 构造URL
|
|
|
url = f'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={date}&leftTicketDTO.from_station={city_data[from_city]}&leftTicketDTO.to_station={city_data[to_city]}&purpose_codes=ADULT'
|
|
|
|
|
|
# 向指定的URL发送一个带有特定头信息的GET请求,并获取服务器的响应
|
|
|
headers = {
|
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
|
|
|
'Cookie': '_uab_collina=171195922365279549520858; JSESSIONID=19E602A91EBCFCD88A8BBDF5DABDE80F; _jc_save_wfdc_flag=dc; _jc_save_fromStation=%u682A%u6D32%2CZZQ; _jc_save_toStation=%u957F%u6C99%2CCSQ; BIGipServerotn=1978138890.24610.0000; BIGipServerpassport=837288202.50215.0000; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; route=495c805987d0f5c8c84b14f60212447d; _jc_save_fromDate=2024-05-27; _jc_save_toDate=2024-05-27'
|
|
|
}
|
|
|
response = requests.get(url=url, headers=headers)
|
|
|
|
|
|
# 检查请求状态
|
|
|
if response.status_code != 200: # 判断http响应状态码是否成功
|
|
|
messagebox.showerror("错误", f"请求失败,状态码: {response.status_code}")
|
|
|
return
|
|
|
|
|
|
# 解析数据
|
|
|
try:
|
|
|
json_data = response.json()
|
|
|
result = json_data['data']['result']
|
|
|
except (KeyError, json.JSONDecodeError):
|
|
|
messagebox.showerror("错误", "解析数据失败,可能是服务器返回格式错误。")
|
|
|
return
|
|
|
|
|
|
# 创建 PrettyTable 表格
|
|
|
tb = pt.PrettyTable()
|
|
|
tb.field_names = [
|
|
|
'序号',
|
|
|
'车次',
|
|
|
'出发时间',
|
|
|
'到达时间',
|
|
|
'耗时',
|
|
|
'特等座',
|
|
|
'一等',
|
|
|
'二等',
|
|
|
'软卧',
|
|
|
'硬卧',
|
|
|
'硬座',
|
|
|
'无座',
|
|
|
]
|
|
|
page = 1
|
|
|
|
|
|
# 填充表格数据
|
|
|
for i in result:
|
|
|
index = i.split('|')
|
|
|
num = index[3]
|
|
|
#根据车次类型进行筛选
|
|
|
train_num = index[3]
|
|
|
start_time = index[8]
|
|
|
end_time = index[9]
|
|
|
use_time = index[10]
|
|
|
topGrade = index[32]
|
|
|
first_class = index[31]
|
|
|
second_class = index[30]
|
|
|
hard_sleeper = index[28]
|
|
|
hard_seat = index[29]
|
|
|
no_seat = index[26]
|
|
|
soft_sleeper = index[23]
|
|
|
|
|
|
# 根据车次类型筛选
|
|
|
if train_type != "全部" and train_type not in train_num:
|
|
|
continue
|
|
|
tb.add_row([
|
|
|
page,
|
|
|
num,
|
|
|
start_time,
|
|
|
end_time,
|
|
|
use_time,
|
|
|
topGrade,
|
|
|
first_class,
|
|
|
second_class,
|
|
|
soft_sleeper,
|
|
|
hard_sleeper,
|
|
|
hard_seat,
|
|
|
no_seat,
|
|
|
])
|
|
|
page += 1
|
|
|
|
|
|
# 显示表格
|
|
|
result_text.config(state=tk.NORMAL)
|
|
|
result_text.delete('1.0', tk.END)
|
|
|
result_text.insert(tk.END, str(tb))
|
|
|
result_text.config(state=tk.DISABLED)
|
|
|
|
|
|
# 创建主窗口
|
|
|
root = tk.Tk()
|
|
|
root.title("火车票查询")
|
|
|
|
|
|
# 创建车次类型选择的下拉列表
|
|
|
train_type_label = ttk.Label(root, text="车次类型:")
|
|
|
train_type_label.grid(row=3, column=0, padx=5, pady=5, sticky="e")
|
|
|
train_type_combobox = ttk.Combobox(root, values=["全部", "G","S","D", "T", "K"])
|
|
|
train_type_combobox.grid(row=3, column=1, padx=5, pady=5)
|
|
|
train_type_combobox.current(0)
|
|
|
|
|
|
# 创建出发城市输入框和标签
|
|
|
from_city_label = ttk.Label(root, text="出发城市:")
|
|
|
from_city_label.grid(row=0, column=0, padx=5, pady=5, sticky="e")
|
|
|
from_city_combobox = ttk.Combobox(root, values=[])
|
|
|
from_city_combobox.grid(row=0, column=1, padx=5, pady=5)
|
|
|
|
|
|
# 创建目的城市输入框和标签
|
|
|
to_city_label = ttk.Label(root, text="目的城市:")
|
|
|
to_city_label.grid(row=1, column=0, padx=5, pady=5, sticky="e")
|
|
|
to_city_combobox = ttk.Combobox(root, values=[])
|
|
|
to_city_combobox.grid(row=1, column=1, padx=5, pady=5)
|
|
|
|
|
|
# 创建出发日期输入框和标签
|
|
|
date_label = ttk.Label(root, text="出发日期:")
|
|
|
date_label.grid(row=2, column=0, padx=5, pady=5, sticky="e")
|
|
|
date_entry = ttk.Entry(root)
|
|
|
date_entry.grid(row=2, column=1, padx=5, pady=5)
|
|
|
|
|
|
# 创建查询按钮
|
|
|
search_button = ttk.Button(root, text="查询", command=search_trains)
|
|
|
search_button.grid(row=10, columnspan=2, padx=5, pady=5)
|
|
|
|
|
|
# 创建显示结果的文本框
|
|
|
result_text = tk.Text(root, height=20, width=100)
|
|
|
result_text.grid(row=4, columnspan=2, padx=5, pady=5)
|
|
|
result_text.config(state=tk.DISABLED)
|
|
|
|
|
|
# 创建欢迎文本框
|
|
|
welcome_label = ttk.Label(root, text="欢迎来到cb的查票系统")
|
|
|
|
|
|
# 设置字体大小
|
|
|
welcome_label.config(font=("微软雅黑", 20)) # 这里使用了微软雅黑字体,字体大小为20
|
|
|
welcome_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")# 添加到左上角
|
|
|
|
|
|
# 更新城市下拉列表
|
|
|
def update_city_comboboxes():
|
|
|
cities = list(city_data.keys())
|
|
|
cities.sort()
|
|
|
from_city_combobox['values'] = cities
|
|
|
to_city_combobox['values'] = cities
|
|
|
|
|
|
# 初始化城市数据
|
|
|
try:
|
|
|
with open('city.json', 'r', encoding='utf-8') as f:
|
|
|
city_data = json.load(f)
|
|
|
update_city_comboboxes()
|
|
|
except FileNotFoundError:
|
|
|
messagebox.showerror("错误", "城市数据文件不存在,请确保 city.json 文件在当前目录下。")
|
|
|
except json.JSONDecodeError:
|
|
|
messagebox.showerror("错误", "城市数据文件格式错误,请确保 city.json 文件内容为有效的 JSON 格式。")
|
|
|
|
|
|
root.mainloop()
|