Skip to content

Instantly share code, notes, and snippets.

@ProfAndreaPollini
Last active May 19, 2025 07:54
Show Gist options
  • Save ProfAndreaPollini/122d465197c8a9841a03a6cfa95acb1d to your computer and use it in GitHub Desktop.
Save ProfAndreaPollini/122d465197c8a9841a03a6cfa95acb1d to your computer and use it in GitHub Desktop.
import requests
from bs4 import BeautifulSoup # Useremo BeautifulSoup
import re # Per estrarre il numero dal testo
def get_solar_irradiation_by_tag_index(tag_name_to_find, index_to_select):
"""
Legge i dati di irraggiamento solare dal sito starrylink.it per la webcam di Brescia
selezionando un tag specifico in base al suo nome e al suo indice nella lista di tutti
i tag con quel nome.
Args:
tag_name_to_find (str): Il nome del tag HTML da cercare (es. "font").
index_to_select (int): L'indice (0-based) del tag da selezionare dalla lista di tutti i tag trovati.
Returns:
int: Il valore dell'irraggiamento solare in W/m², se trovato.
None: Se si verifica un errore o il dato non viene trovato.
"""
url = "https://www.starrylink.it/webcam/brescia/vp2/bscastle.htm"
valore_irraggiamento = None
print(f"Tentativo di connessione a: {url}")
try:
response = requests.get(url, timeout=15)
print(f"Status code della risposta: {response.status_code}")
response.raise_for_status() # Solleva un'eccezione per risposte HTTP errate
soup = BeautifulSoup(response.content, 'html.parser')
print("HTML della pagina parsato con BeautifulSoup.")
# Trova tutti i tag con il nome specificato
all_specified_tags = soup.find_all(tag_name_to_find)
print(f"Trovati {len(all_specified_tags)} tag '<{tag_name_to_find}>' nella pagina.")
if len(all_specified_tags) > index_to_select:
# Seleziona il tag all'indice specificato
target_element = all_specified_tags[index_to_select]
print(f"Debug: Selezionato il tag '<{tag_name_to_find}>' all'indice {index_to_select}.")
# Estrai il testo dall'elemento.
value_str_raw = target_element.get_text(strip=True)
print(f"Debug: Testo grezzo dall'elemento (tag='{tag_name_to_find}', index={index_to_select}): '{value_str_raw}'")
if value_str_raw:
# Cerca una o più cifre nel testo estratto
match = re.search(r'\d+', value_str_raw)
if match:
valore_irraggiamento = int(match.group(0))
print(f"Debug: Valore numerico estratto: {valore_irraggiamento}")
else:
print(f"Errore: Nessun numero trovato nel testo '{value_str_raw}' ottenuto dal tag '{tag_name_to_find}' all'indice {index_to_select}.")
else:
print(f"Errore: Il tag '{tag_name_to_find}' all'indice {index_to_select} non ha contenuto testuale.")
else:
print(f"Errore: Non ci sono abbastanza tag '<{tag_name_to_find}>' (trovati {len(all_specified_tags)}, richiesto indice {index_to_select}). L'indice è fuori range.")
except requests.exceptions.HTTPError as http_err:
print(f"Errore HTTP: {http_err}")
except requests.exceptions.ConnectionError as conn_err:
print(f"Errore di connessione: {conn_err}")
except requests.exceptions.Timeout as timeout_err:
print(f"Errore di timeout: {timeout_err}")
except requests.exceptions.RequestException as req_err:
print(f"Errore generico durante la richiesta: {req_err}")
except IndexError: # Specifico per l'accesso all'indice errato
print(f"Errore: L'indice {index_to_select} è fuori range per i tag '<{tag_name_to_find}>' (trovati {len(all_specified_tags)}).")
except Exception as e:
print(f"Si è verificato un errore imprevisto: {e}")
return valore_irraggiamento
if __name__ == '__main__':
# Parametri basati sull'input: document.getElementsByTagName("font")[55]
target_html_tag_name = "font"
target_html_tag_index = 55 # JavaScript usa indici 0-based, quindi [55] è il 56° elemento.
print(f"Esecuzione dello script per recuperare l'irraggiamento solare usando il tag '{target_html_tag_name}' all'indice {target_html_tag_index}")
irraggiamento = get_solar_irradiation_by_tag_index(target_html_tag_name, target_html_tag_index)
if irraggiamento is not None:
print(f"\nL'irraggiamento solare attuale (ottenuto tramite indice di tag) è: {irraggiamento} W/m²")
else:
print("\nNon è stato possibile recuperare il dato di irraggiamento solare tramite indice di tag.")
import requests
import json
from datetime import datetime, timezone
import pytz # Per una gestione robusta dei fusi orari
# Coordinate geografiche approssimative per Brescia
BRESCIA_LATITUDE = 45.5389
BRESCIA_LONGITUDE = 10.2207
BRESCIA_TIMEZONE = "Europe/Rome"
def get_solar_irradiance_brescia():
"""
Recupera i dati di irraggiamento solare attuali e previsti per oggi per Brescia
utilizzando l'API di Open-Meteo.
Restituisce:
dict: Un dizionario contenente i dati orari di irraggiamento (GHI, DNI, DHI)
e l'ora corrispondente, oppure None se si verifica un errore.
Include anche le unità di misura.
Esempio di output per un'ora specifica:
{
"latitude": 45.54,
"longitude": 10.22,
"timezone": "Europe/Rome",
"elevation_m": 149.0,
"units": { ... },
"current_or_latest_past_hour_data": {
"time_iso8601": "2024-05-10T14:00",
"ghi_w_m2": 750.5,
"dni_w_m2": 850.2,
"dhi_w_m2": 150.8
},
"all_today_hourly_data": [ ...lista di dati orari... ]
}
"""
api_url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": BRESCIA_LATITUDE,
"longitude": BRESCIA_LONGITUDE,
"hourly": "shortwave_radiation,direct_normal_irradiance,diffuse_radiation,direct_radiation",
"timezone": BRESCIA_TIMEZONE,
"forecast_days": 1,
}
try:
response = requests.get(api_url, params=params)
response.raise_for_status()
data = response.json()
if not data or "hourly" not in data or "hourly_units" not in data:
print("Errore: Dati mancanti o struttura inattesa nella risposta dell'API.")
return None
hourly_data = data["hourly"]
times = hourly_data.get("time", [])
ghi_values = hourly_data.get("shortwave_radiation", [])
dni_values = hourly_data.get("direct_normal_irradiance", [])
dhi_values = hourly_data.get("diffuse_radiation", [])
if not all([times, ghi_values, dni_values, dhi_values]):
print("Errore: Uno o più set di dati orari sono mancanti.")
return None
processed_data = []
for i in range(len(times)):
processed_data.append({
"time_iso8601": times[i],
"ghi_w_m2": ghi_values[i] if ghi_values[i] is not None else 0,
"dni_w_m2": dni_values[i] if dni_values[i] is not None else 0,
"dhi_w_m2": dhi_values[i] if dhi_values[i] is not None else 0,
})
# Ottieni il fuso orario di Brescia
brescia_pytz_timezone = pytz.timezone(BRESCIA_TIMEZONE)
# Ottieni l'ora attuale, consapevole del fuso orario
now_brescia_tz_aware = datetime.now(brescia_pytz_timezone)
current_hour_data = None
latest_valid_index = -1
for i, t_str in enumerate(times):
# 1. Parsa la stringa di tempo dall'API in un datetime naive
naive_api_datetime = datetime.fromisoformat(t_str)
# 2. Rendi il datetime consapevole del fuso orario (lo stesso che abbiamo richiesto all'API)
aware_api_datetime = brescia_pytz_timezone.localize(naive_api_datetime)
# 3. Ora il confronto è tra due datetime consapevoli del fuso orario
if aware_api_datetime <= now_brescia_tz_aware:
latest_valid_index = i
else:
break
if latest_valid_index != -1:
current_hour_data = processed_data[latest_valid_index]
elif processed_data:
current_hour_data = processed_data[0]
return {
"latitude": data.get("latitude"),
"longitude": data.get("longitude"),
"timezone": data.get("timezone"),
"elevation_m": data.get("elevation"),
"units": data.get("hourly_units"),
"current_or_latest_past_hour_data": current_hour_data,
"all_today_hourly_data": processed_data
}
except requests.exceptions.RequestException as e:
print(f"Errore durante la richiesta all'API Open-Meteo: {e}")
return None
except json.JSONDecodeError:
print("Errore: Impossibile decodificare la risposta JSON dall'API Open-Meteo.")
return None
except pytz.exceptions.AmbiguousTimeError as e:
print(f"Errore di fuso orario ambiguo (possibile durante il cambio ora legale/solare): {e}")
print("Potrebbe essere necessario gestire questo caso specifico se si verifica frequentemente.")
return None
except Exception as e:
print(f"Si è verificato un errore imprevisto: {e.__class__.__name__} - {e}")
return None
if __name__ == "__main__":
print(f"Recupero dei dati di irraggiamento solare per Brescia (Lat: {BRESCIA_LATITUDE}, Lon: {BRESCIA_LONGITUDE})...")
# Nota: la data di esecuzione reale sarà quella corrente quando si esegue lo script.
# L'esempio nel prompt era per il 9 maggio 2025.
print(f"Data e ora correnti (fuso orario di Brescia): {datetime.now(pytz.timezone(BRESCIA_TIMEZONE)).isoformat()}")
irradiance_data = get_solar_irradiance_brescia()
if irradiance_data:
print("\n--- Riepilogo ---")
print(f"Latitudine: {irradiance_data['latitude']:.4f}, Longitudine: {irradiance_data['longitude']:.4f}")
print(f"Fuso orario: {irradiance_data['timezone']}, Altitudine: {irradiance_data['elevation_m']} m")
print("Unità di misura:")
if irradiance_data['units']:
for key, value in irradiance_data['units'].items():
print(f" {key}: {value}")
else:
print(" Unità non disponibili.")
if irradiance_data["current_or_latest_past_hour_data"]:
print("\n--- Dati per l'ora corrente o l'ultima ora passata disponibile ---")
current_data = irradiance_data["current_or_latest_past_hour_data"]
ghi_unit = irradiance_data.get('units', {}).get('shortwave_radiation', 'W/m²')
dni_unit = irradiance_data.get('units', {}).get('direct_normal_irradiance', 'W/m²')
dhi_unit = irradiance_data.get('units', {}).get('diffuse_radiation', 'W/m²')
print(f" Ora: {current_data['time_iso8601']}")
print(f" GHI (Irraggiamento Globale Orizzontale): {current_data['ghi_w_m2']} {ghi_unit}")
print(f" DNI (Irraggiamento Diretto Normale): {current_data['dni_w_m2']} {dni_unit}")
print(f" DHI (Irraggiamento Diffuso Orizzontale): {current_data['dhi_w_m2']} {dhi_unit}")
else:
print("\n--- Nessun dato disponibile per l'ora corrente o passata più recente ---")
# print("\n--- Tutti i dati orari per oggi ({len(irradiance_data['all_today_hourly_data'])} voci) ---")
# for i, hourly_entry in enumerate(irradiance_data["all_today_hourly_data"]):
# if i < 5 or i > len(irradiance_data["all_today_hourly_data"]) - 6 : # Mostra solo inizio e fine se lungo
# print(f" Ora: {hourly_entry['time_iso8601']}, GHI: {hourly_entry['ghi_w_m2']}, DNI: {hourly_entry['dni_w_m2']}, DHI: {hourly_entry['dhi_w_m2']}")
# elif i == 5:
# print(" ...")
else:
print("Nessun dato recuperato.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment