import webbrowser
webbrowser.open("https://ai.csdn.net/?utm_source=cknow_pc_ntoolbar") # 默认浏览器打开
webbrowser.open_new_tab("https://8000.com") # 新标签页打开
import tkinter as tk
import numpy as np
from datetime import datetime, timedelta
import random
from urllib.request import urlopen
from lxml import etree
import chardet
class WeatherForecastApp:
def __init__(self, root):
self.root = root
self.root.title("24 小时天气预报 - 南昌")
self.root.geometry("900x600")
self.root.configure(bg="#f0f8ff")
# 初始化数据
self.current_time = datetime.now()
self.temperature_data, self.weather_conditions = self.fetch_weather_data()
# 创建顶部标题
self.title_label = tk.Label(
root,
text=f"{self.current_time.strftime('%Y 年%m月%d日')} 24小时天气预报 - 南昌",
font=("微软雅黑", 16, "bold"),
bg="#4682b4",
fg="white",
padx=20,
pady=10
)
self.title_label.pack(fill=tk.X)
# 创建主框架
self.main_frame = tk.Frame(root, bg="#f0f8ff")
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# 创建左侧信息面板
self.info_frame = tk.Frame(self.main_frame, bg="#e6f2ff", bd=2, relief=tk.RAISED)
self.info_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 20), pady=10)
# 当前天气信息
current_temp = self.temperature_data[-1][1]
current_weather_condition = self.weather_conditions[-1]
tk.Label(self.info_frame, text="当前天气", font=("微软雅黑", 12, "bold"), bg="#e6f2ff").pack(pady=(10, 5))
self.current_weather = tk.StringVar()
self.current_weather.set(f" 温度: {current_temp}°C\n条件: {current_weather_condition}")
tk.Label(self.info_frame, textvariable=self.current_weather, bg="#e6f2ff", justify=tk.LEFT).pack(pady=5)
# 预测信息
tk.Label(self.info_frame, text="预测信息", font=("微软雅黑", 12, "bold"), bg="#e6f2ff").pack(pady=(15, 5))
self.forecast_info = tk.StringVar()
self.update_forecast_info()
tk.Label(self.info_frame, textvariable=self.forecast_info, bg="#e6f2ff", justify=tk.LEFT).pack(pady=5)
# 创建图表区域
self.chart_frame = tk.Frame(self.main_frame, bg="white", bd=2, relief=tk.SUNKEN)
self.chart_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, pady=10)
self.canvas = tk.Canvas(self.chart_frame, bg="white", width=600, height=400)
self.canvas.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 创建控制面板
self.control_frame = tk.Frame(root, bg="#f0f8ff")
self.control_frame.pack(fill=tk.X, padx=20, pady=(0, 10))
self.update_btn = tk.Button(
self.control_frame,
text="更新预测",
command=self.update_forecast,
bg="#4caf50",
fg="white",
font=("微软雅黑", 10),
padx=15
)
self.update_btn.pack(side=tk.LEFT)
self.simulate_btn = tk.Button(
self.control_frame,
text="模拟变化",
command=self.toggle_simulation,
bg="#2196f3",
fg="white",
font=("微软雅黑", 10),
padx=15
)
self.simulate_btn.pack(side=tk.LEFT, padx=10)
self.status_var = tk.StringVar()
self.status_var.set(" 就绪")
tk.Label(self.control_frame, textvariable=self.status_var, bg="#f0f8ff", font=("微软雅黑", 10)).pack(side=tk.RIGHT)
# 初始化绘图
self.draw_chart()
self.simulation_active = False
def fetch_weather_data(self):
try:
url = "https://tianqi.2345.com/nanchang/58606.htm"
response = urlopen(url)
html = response.read()
# 检测网页编码
result = chardet.detect(html)
encoding = result['encoding']
html = html.decode(encoding)
tree = etree.HTML(html)
# 提取温度和天气状况数据
temperature_data = []
weather_conditions = []
now = datetime.now()
# 这里需要根据实际网页结构调整 XPath
temp_nodes = tree.xpath('//div[@class="hours-weather"]//span[@class="tem"]/text()')
weather_nodes = tree.xpath('//div[@class="hours-weather"]//span[@class="wea"]/text()')
for i in range(min(24, len(temp_nodes), len(weather_nodes))):
temp = float(temp_nodes[i].replace('℃', ''))
weather = weather_nodes[i]
time_point = now - timedelta(hours=23 - i)
temperature_data.append((time_point, temp))
weather_conditions.append(weather)
return temperature_data, weather_conditions
except Exception as e:
print(f"获取天气数据时出错: {e}")
# 生成初始数据作为备用
return self.generate_initial_data(), ["晴天"] * 24
def generate_initial_data(self):
"""生成初始24小时温度数据"""
# 使用NumPy创建时间序列
hours = np.arange(24)
# 使用正弦函数模拟温度变化 (白天高,夜晚低)
base_temp = 20 + 8 * np.sin(2 * np.pi * (hours - 6) / 24)
# 添加随机波动
random_variation = np.random.normal(0, 1.5, 24)
temperatures = np.round(base_temp + random_variation, 1)
# 创建时间-温度数据对
now = datetime.now()
data = []
for i, temp in enumerate(temperatures):
time_point = now - timedelta(hours=23 - i)
data.append((time_point, temp))
return data
def draw_chart(self):
"""在画布上绘制温度折线图"""
self.canvas.delete("all")
# 获取画布尺寸
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
if canvas_width < 100 or canvas_height < 100:
return # 防止初始化时尺寸过小
# 设置边距
margin = 50
chart_width = canvas_width - 2 * margin
chart_height = canvas_height - 2 * margin
# 绘制坐标轴
self.canvas.create_line(margin, margin, margin, margin + chart_height, width=2) # Y轴
self.canvas.create_line(margin, margin + chart_height, margin + chart_width, margin + chart_height, width=2) # X轴
# 计算温度范围
temps = [item[1] for item in self.temperature_data]
min_temp = min(temps)
max_temp = max(temps)
temp_range = max_temp - min_temp
temp_range = max(temp_range, 12) # 确保最小范围
# 添加Y轴刻度和标签
for i in range(6): # 6个刻度
value = min_temp + (i * temp_range / 5)
y = margin + chart_height - (i * chart_height / 5)
self.canvas.create_line(margin - 5, y, margin, y, width=1)
self.canvas.create_text(margin - 10, y, text=f"{value:.1f}°C", anchor="e", font=("Arial", 9))
# 添加X轴刻度和标签
points = []
for i, (time_point, temp) in enumerate(self.temperature_data):
x = margin + (i * chart_width / 23)
y = margin + chart_height - ((temp - min_temp) / temp_range) * chart_height
points.append((x, y))
# 每2小时显示一个时间标签
if i % 2 == 0:
self.canvas.create_line(x, margin + chart_height, x, margin + chart_height + 5, width=1)
self.canvas.create_text(
x,
margin + chart_height + 15,
text=time_point.strftime("%H:%M"),
font=("Arial", 9)
)
# 在时间标签下方显示天气状况
weather = self.weather_conditions[i]
self.canvas.create_text(
x,
margin + chart_height + 30,
text=weather,
font=("Arial", 9)
)
# 绘制折线
if len(points) > 1:
for i in range(1, len(points)):
x1, y1 = points[i - 1]
x2, y2 = points[i]
self.canvas.create_line(x1, y1, x2, y2, fill="#1e88e5", width=3, smooth=True)
# 绘制数据点
for x, y in points:
# 根据温度选择点颜色
temp = min_temp + ((margin + chart_height - y) / chart_height) * temp_range
color = "#ff5252" if temp > 25 else "#1e88e5" # 高温红色,低温蓝色
self.canvas.create_oval(x - 5, y - 5, x + 5, y + 5, fill=color, outline=color)
# 在点上方显示温度值
if points.index((x, y)) % 3 == 0: # 每3小时显示一次温度
self.canvas.create_text(x, y - 15, text=f"{temp:.1f}°C", font=("Arial", 9), fill="#333")
# 添加当前时间标记
last_x, last_y = points[-1]
self.canvas.create_line(last_x, margin, last_x, margin + chart_height, fill="#4caf50", dash=(4, 2), width=2)
self.canvas.create_text(
last_x,
margin - 20,
text="当前时间",
fill="#4caf50",
font=("Arial", 10, "bold")
)
# 添加标题
self.canvas.create_text(
canvas_width / 2,
20,
text="24小时温度变化趋势 - 南昌",
font=("微软雅黑", 12, "bold"),
fill="#333"
)
def update_forecast_info(self):
"""更新预测信息"""
temps = [item[1] for item in self.temperature_data]
max_temp = max(temps)
min_temp = min(temps)
avg_temp = np.mean(temps)
# 找出最高温和最低温的时间
max_index = temps.index(max_temp)
min_index = temps.index(min_temp)
max_time = self.temperature_data[max_index][0].strftime("%H:%M")
min_time = self.temperature_data[min_index][0].strftime("%H:%M")
info = f"最高温度: {max_temp:.1f}°C ({max_time})\n"
info += f"最低温度: {min_temp:.1f}°C ({min_time})\n"
info += f"平均温度: {avg_temp:.1f}°C\n"
info += f"天气变化: {random.choice([' 稳定', '逐渐升温', '小幅波动'])}"
self.forecast_info.set(info)
def update_forecast(self):
"""更新天气预报"""
self.status_var.set(" 更新预测中...")
self.root.update()
# 重新获取天气数据
self.temperature_data, self.weather_conditions = self.fetch_weather_data()
# 更新当前天气显示
current_temp = self.temperature_data[-1][1]
current_weather_condition = self.weather_conditions[-1]
self.current_weather.set(f" 温度: {current_temp}°C\n条件: {current_weather_condition}")
# 更新预测信息
self.update_forecast_info()
# 重绘图表
self.draw_chart()
self.status_var.set(" 预测已更新")
def toggle_simulation(self):
"""切换模拟状态"""
if not self.simulation_active:
self.simulation_active = True
self.simulate_btn.config(text=" 停止模拟")
self.status_var.set(" 模拟运行中...")
self.simulate_changes()
else:
self.simulation_active = False
self.simulate_btn.config(text=" 模拟变化")
self.status_var.set(" 模拟已停止")
def simulate_changes(self):
"""模拟天气变化"""
if not self.simulation_active:
return
# 更新数据:移除最旧的数据点,添加新的数据点
self.temperature_data.pop(0)
self.weather_conditions.pop(0)
# 基于当前时间生成新数据点
current_time = datetime.now()
# 基于前一个温度值生成新温度(加入随机变化)
last_temp = self.temperature_data[-1][1]
hour = current_time.hour
# 根据一天中的时间调整变化方向
if 6 <= hour < 12: # 早晨升温
change = random.uniform(0.1, 1.5)
elif 12 <= hour < 18: # 下午可能降温
change = random.uniform(-0.5, 0.5)
else: # 晚上降温
change = random.uniform(-1.5, -0.1)
new_temp = round(last_temp + change, 1)
new_weather = random.choice([" 晴天", "多云", "小雨", "阴天", "雷阵雨"])
self.temperature_data.append((current_time, new_temp))
self.weather_conditions.append(new_weather)
# 更新UI
self.current_weather.set(f" 温度: {new_temp}°C\n条件: {new_weather}")
self.update_forecast_info()
self.draw_chart()
# 安排下一次更新
self.root.after(990000, self.simulate_changes)
if __name__ == "__main__":
root = tk.Tk()
app = WeatherForecastApp(root)
root.mainloop() 不能用import chardet 库和其他外置库,只能用import tkinter as tk
import numpy as np
from datetime import datetime, timedelta
import random
from urllib.request import urlopen
from lxml import etree 库,修改后的完整代码
最新发布