Jan-30-2022, 12:32 AM
Added extended and sunrise/sunset to the app. Only showing 2 day extended although the information received is for seven day.
#! /usr/bin/env python3 from bs4 import BeautifulSoup as bs import requests, json, re, sys from time import strftime from datetime import datetime, timedelta from PyQt6.QtCore import (Qt, QTimer, QTime) from PyQt6.QtGui import (QImage, QPixmap) from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QPushButton) class Weather: def __init__(self): # Get location - lat and long location = json.loads(requests.get('http://ipinfo.io/json').text)['loc'] lat, lon = location.split(',') print(location) # Get weather page from forecast.weather.gov page = requests.get(f'https://forecast.weather.gov/MapClick.php?lat={lat}&lon={lon}') # Get sunrise/sunset and format sunurl = 'https://api.sunrise-sunset.org/json' params = {'lat': lat, 'lon': lon, 'formatted': 0, 'date': 'today'} input_format = '%Y-%m-%dT%H:%M:%S+00:00' output_format = '%I:%M:%S %p' sunpage = requests.get(sunurl, params).json() sunrise = sunpage['results']['sunrise'] sunrise = datetime.strptime(sunrise, input_format) sunrise = sunrise + timedelta() sunrise = sunrise.strftime(output_format) sunset = sunpage['results']['sunset'] sunset = datetime.strptime(sunset, input_format) sunset = sunset + timedelta() sunset = sunset.strftime(output_format) # Create the sun dict sun = {} sun['sunrise'] = sunrise sun['sunset'] = sunset # Create the soup soup = bs(page.text, 'html.parser') # Create some dicts for storing data self.data = {} summary = {} current_conditions = {} extended_forcast = {} # Find the header we want and store in the data dict self.data['header'] = f"{soup.find('h2', attrs={'class':'panel-title'}).text}" # Find current condition summary and data weather = soup.find('div', attrs={'id': 'current_conditions-summary'}) summary['img'] = f"https://forecast.weather.gov/{weather.find('img')['src']}" summary['condition'] = weather.find('p', attrs={'class': 'myforecast-current'}).text summary['temp f'] = weather.find('p', attrs={'class': 'myforecast-current-lrg'}).text summary['temp c'] = weather.find('p', attrs={'class': 'myforecast-current-sm'}).text # Find detail data from soup table = soup.find('div', attrs={'id': 'current_conditions_detail'}) # Find the detail header/left td in table and add to dict as keys for text in table.findAll('b'): current_conditions[text.text] = None # Find the data on the right td and add to current_conditions dict for key in current_conditions.keys(): for text in table.findAll('tr'): # Using this to get rid of excessive white space in the last dict entry if key in text.text.strip(): text = re.sub(key, '', text.text.strip()) current_conditions[key] = text.replace('\n', '').strip() # Get extened forcast days = [] imgs = [] extended = soup.findAll('div', attrs={'class': 'tombstone-container'}) for line in extended: imgs.append(f"https://forecast.weather.gov/{line.find('img')['src']}") for day in extended: days.append(day.text.strip()) # Add everything to the data dict self.data['summary'] = summary self.data['details'] = current_conditions self.data['sun'] = sun self.data['extended'] = (days,imgs) class Window(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setFixedSize(450,500) # Iniate the Weather class weather = Weather() self.summary = weather.data['summary'] self.details = weather.data['details'] self.sun = weather.data['sun'] self.extended = weather.data['extended'] self.setWindowTitle('PyQt6 Weather App') # Create main container container = QGridLayout() cbox = QHBoxLayout() sbox = QHBoxLayout() # Create data container dgrid = QGridLayout() dgrid.setSpacing(1) dgrid.setContentsMargins(2, 2, 2, 2) dframe = QFrame() dframe.setFrameStyle(1) dframe.setFrameShadow(QFrame.Shadow.Sunken) dframe.setLayout(dgrid) # Create the header header = QLabel('PyQt6 Weather App') header.setAlignment(Qt.AlignmentFlag.AlignCenter) header.setStyleSheet('font-size: 18px; background-color: lightgray; padding: 5 3 5 3; \ font-weight: bold; border: 1px solid gray; color:steelblue;') # Create local header self.loc_header = QLabel(f'Current Conditions at {weather.data["header"]}') self.loc_header.setAlignment(Qt.AlignmentFlag.AlignCenter) self.loc_header.setStyleSheet('font-size: 12px; color: navy; background-color: lightgray; \ padding: 5, 3, 5, 3; border: 1px solid gray; font-weight: bold;') # Get first init image img_url = self.summary['img'] image = QImage() image.loadFromData(requests.get(img_url).content) # Create image label self.img_label = QLabel() self.img_label.setStyleSheet('padding: 3 3 3 3;') self.img_label.setPixmap(QPixmap(image)) # Create detail labels i = 0 self.myvlabels = [] hlabels = [] for key, value in self.details.items(): self.myvlabels.append(value) hlabels.append(key) hlabels[i] = QLabel(f'<b>{key}</b>:') hlabels[i].setStyleSheet('border: 1px solid lightgray; padding: 0 0 0 8;') self.myvlabels[i] = QLabel(value) self.myvlabels[i].setStyleSheet('border: 1px solid lightgray; padding 0 0 0 0;') dgrid.addWidget(hlabels[i], i, 1, 1, 1) dgrid.addWidget(self.myvlabels[i], i, 2, 1, 1) i += 1 # Create sunrise/sunset label sunlabel = QLabel(f'<b>Sunrise</b>: {self.sun["sunrise"]} - <b>Sunset</b>: {self.sun["sunset"]}') sunlabel.setFrameStyle(1) sunlabel.setFrameShadow(QFrame.Shadow.Sunken) sbox.addWidget(sunlabel) # Create current conditions label text = f'<b>Currently</b>: {self.summary["condition"]} {self.summary["temp f"]} / {self.summary["temp c"]}' self.current_label = QLabel(text) self.current_label.setFrameStyle(1) self.current_label.setFrameShadow(QFrame.Shadow.Sunken) # Create a clock self.clock = QLabel(f'Current Time: <font color="navy">{strftime("%I:%M:%S %p")}</font>') self.clock.setFrameStyle(1) self.clock.setFrameShadow(QFrame.Shadow.Sunken) # Compact current data and clock cbox.addWidget(self.current_label) cbox.addWidget(self.clock) # Add data widget to data container dgrid.addWidget(self.img_label, 0, 0, len(self.details), 1) # Add extended forcast exbox = QGridLayout() exbox.setSpacing(20) exbox.setContentsMargins(8,8,8,8) exbox_frame = QFrame() exbox_frame.setLayout(exbox) exbox_frame.setFrameStyle(1) exbox_frame.setFrameShadow(QFrame.Shadow.Sunken) group_box = QHBoxLayout() tbox = QHBoxLayout() exlabel = QLabel('Extended Forecast') exlabel.setStyleSheet('background-color: lightgray; padding: 5,5,5,5; font-weight: bold; \ border: 1px solid gray;') exbox.addWidget(exlabel, 0, 0, 1, 1) i = 0 for day in self.extended[0]: if i < 4: img_url = self.extended[1][i] image = QImage() image.loadFromData(requests.get(img_url).content) days_img = QLabel() days_img.setPixmap(QPixmap(image)) group_box.addWidget(days_img) tbox.addWidget(QLabel(day)) exbox.addLayout(group_box, 1, i, 1, 1, Qt.AlignmentFlag.AlignTop) exbox.addLayout(tbox, 2, i, 1, 1, Qt.AlignmentFlag.AlignTop) i += 1 # Add widgets to main container grid container.addWidget(header, 0, 0, 1, 1, Qt.AlignmentFlag.AlignTop) container.addWidget(self.loc_header, 1, 0, 1, 1, Qt.AlignmentFlag.AlignTop) container.addWidget(dframe, 2, 0, 1, 1, Qt.AlignmentFlag.AlignTop) container.addLayout(sbox, 3, 0, 1, 1, Qt.AlignmentFlag.AlignTop) container.addLayout(cbox, 4, 0, 1, 1, Qt.AlignmentFlag.AlignTop) container.addWidget(exbox_frame, 5, 0, 1, 1) # Setup the clock timer / updates every 1 second clock_timer = QTimer(self) clock_timer.timeout.connect(self.clock_update) clock_timer.start(1000) # Setup the update timer / updates every 5 minutes update_timer = QTimer(self) update_timer.timeout.connect(self.update) update_timer.start(3000000) widget = QWidget() widget.setLayout(container) self.setCentralWidget(widget) def clock_update(self): self.clock.setText(f'<b>Current Time</b>: <font color="navy">{strftime("%I:%M:%S %p")}</font>') def update(self): # Iniate the Weather class weather = Weather() # Set some variables summary = weather.data['summary'] details = weather.data['details'] # Update the labels img_url = self.summary['img'] image = QImage() image.loadFromData(requests.get(img_url).content) self.img_label.setPixmap(QPixmap(image)) i = 0 for val in details.values(): self.myvlabels[i].setText(val) i += 1 self.current_label.setText(f'<b>Currently</b>: {summary["condition"]} {summary["temp f"]} / {summary["temp c"]}') def main(): app = QApplication(sys.argv) window = Window() window.show() sys.exit(app.exec()) if __name__ == '__main__': main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags