ProyectoFinalPython/app/widgets/WeatherTab.py

125 lines
5.7 KiB
Python

import threading
import requests
from bs4 import BeautifulSoup
from tkinter import Frame, Label, PhotoImage, Tk
from app.widgets.abc import ThreadedTab
import cairosvg
from io import BytesIO
class WeatherTab(ThreadedTab):
def __init__(self, root: Frame | Tk, city: str, **kwargs):
self.city = city
self.weather_info = {}
self.weather_image = None
self.weather_frame = None
self.weather_label = None
self.weather_image_label = None
self.city_label = None
self.real_feel_label = None
self.wind_label = None
self.wind_gusts_label = None
self.air_quality_label = None
super().__init__(root, **kwargs)
def build(self):
self.weather_frame = Frame(self)
self.weather_frame.pack(fill="both", expand=True)
self.city_label = Label(self.weather_frame, text=f"Weather in {self.city}", font=("Helvetica", 16))
self.city_label.grid(row=0, column=0, columnspan=2, pady=10, sticky="ew")
self.weather_image_label = Label(self.weather_frame)
self.weather_image_label.grid(row=1, column=0, padx=10, sticky="ew")
self.weather_label = Label(self.weather_frame, text="", font=("Helvetica", 14))
self.weather_label.grid(row=1, column=1, padx=10, sticky="ew")
self.real_feel_label = Label(self.weather_frame, text="", font=("Helvetica", 12))
self.real_feel_label.grid(row=2, column=1, padx=10, sticky="ew")
self.wind_label = Label(self.weather_frame, text="", font=("Helvetica", 12))
self.wind_label.grid(row=3, column=1, padx=10, sticky="ew")
self.wind_gusts_label = Label(self.weather_frame, text="", font=("Helvetica", 12))
self.wind_gusts_label.grid(row=4, column=1, padx=10, sticky="ew")
self.air_quality_label = Label(self.weather_frame, text="", font=("Helvetica", 12))
self.air_quality_label.grid(row=5, column=1, padx=10, sticky="ew")
self.weather_frame.columnconfigure(0, weight=1)
self.weather_frame.columnconfigure(1, weight=1)
# Ensure the frame fills the entire parent space
self.grid(row=0, column=0, sticky="nsew")
self.master.rowconfigure(0, weight=1)
self.master.columnconfigure(0, weight=1)
def task(self, *args):
self.fetch_weather_data()
self.update_ui()
def fetch_weather_data(self):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
}
search_url = f"https://www.accuweather.com/en/search-locations?query={self.city}"
search_response = requests.get(search_url, headers=headers)
search_soup = BeautifulSoup(search_response.text, 'html.parser')
location_list = search_soup.find('div', class_='locations-list content-module')
if not location_list:
print("Location list not found")
return
location_link = location_list.find('a')['href']
weather_url = f"https://www.accuweather.com{location_link}"
weather_response = requests.get(weather_url, headers=headers)
weather_soup = BeautifulSoup(weather_response.text, 'html.parser')
weather_icon_path = weather_soup.find('svg', class_='weather-icon')['data-src']
weather_icon_url = f"https://www.accuweather.com{weather_icon_path}"
weather_icon_response = requests.get(weather_icon_url, headers=headers)
weather_icon_svg = weather_icon_response.content
# Convert SVG to PNG and resize to 50x50
weather_icon_png = cairosvg.svg2png(bytestring=weather_icon_svg, output_width=50, output_height=50)
weather_icon_image = PhotoImage(data=BytesIO(weather_icon_png).getvalue())
temperature = weather_soup.find('div', class_='temp').text
real_feel = weather_soup.find('div', class_='real-feel').text.strip().replace('RealFeel®', '').strip()
details_container = weather_soup.find('div', class_='details-container')
wind = details_container.find('span', text='Wind').find_next('span', class_='value').text.strip() if details_container else 'N/A'
wind_gusts = details_container.find('span', text='Wind Gusts').find_next('span', class_='value').text.strip() if details_container else 'N/A'
air_quality = details_container.find('span', text='Air Quality').find_next('span', class_='value').text.strip() if details_container else 'N/A'
self.weather_info = {
'icon': weather_icon_image,
'temperature': temperature,
'real_feel': real_feel,
'wind': wind,
'wind_gusts': wind_gusts,
'air_quality': air_quality
}
except Exception as e:
print(f"Error fetching weather data: {e}")
def update_ui(self):
if self.weather_info:
weather_text = f"{self.weather_info['temperature']}"
self.weather_label.config(text=weather_text)
self.weather_image_label.config(image=self.weather_info['icon'])
self.weather_image_label.image = self.weather_info['icon']
self.real_feel_label.config(text=f"RealFeel: {self.weather_info['real_feel']}")
self.wind_label.config(text=f"Wind: {self.weather_info['wind']}")
self.wind_gusts_label.config(text=f"Wind Gusts: {self.weather_info['wind_gusts']}")
self.air_quality_label.config(text=f"Air Quality: {self.weather_info['air_quality']}")
def changeCity(self, city):
self.city = city
self.city_label.config(text=f"Weather in {self.city}")
threading.Thread(target=self.task).start()