Update 12306chapiao.py

main
p5xwq9ihz 10 months ago
parent fb3d252f16
commit 4f9a5ec418

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

Loading…
Cancel
Save