Python Snippets

Automatic Weather Data Fetcher with Forecast Caching

import requests
import json
import os
import time
from datetime import datetime, timedelta

class WeatherFetcher:
    def __init__(self, api_key, cache_duration_hours=1):
        self.api_key = api_key
        self.base_url = "http://api.openweathermap.org/data/2.5"
        self.cache_file = "weather_cache.json"
        self.cache_duration = timedelta(hours=cache_duration_hours)
    
    def _load_cache(self):
        """Load cached weather data if it exists and is still valid"""
        if os.path.exists(self.cache_file):
            with open(self.cache_file, 'r') as f:
                cache_data = json.load(f)
                
            # Check if cache is still valid
            cache_time = datetime.fromisoformat(cache_data['timestamp'])
            if datetime.now() - cache_time < self.cache_duration:
                return cache_data['data']
        return None
    
    def _save_cache(self, data):
        """Save weather data to cache with timestamp"""
        cache_data = {
            'timestamp': datetime.now().isoformat(),
            'data': data
        }
        with open(self.cache_file, 'w') as f:
            json.dump(cache_data, f)
    
    def get_weather(self, city, units='metric'):
        """Fetch current weather for a city (with caching)"""
        # Try to get from cache first
        cached_data = self._load_cache()
        if cached_data and cached_data.get('city') == city:
            print("Using cached data")
            return cached_data
        
        # If not in cache or expired, fetch from API
        try:
            url = f"{self.base_url}/weather"
            params = {
                'q': city,
                'appid': self.api_key,
                'units': units
            }
            
            response = requests.get(url, params=params)
            response.raise_for_status()
            
            data = response.json()
            formatted_data = {
                'city': city,
                'temperature': data['main']['temp'],
                'feels_like': data['main']['feels_like'],
                'humidity': data['main']['humidity'],
                'description': data['weather'][0]['description'],
                'wind_speed': data['wind']['speed'],
                'timestamp': datetime.now().isoformat()
            }
            
            # Save to cache
            self._save_cache(formatted_data)
            return formatted_data
            
        except requests.exceptions.RequestException as e:
            print(f"Error fetching weather data: {e}")
            return None
    
    def get_forecast(self, city, units='metric'):
        """Fetch 5-day weather forecast for a city"""
        try:
            url = f"{self.base_url}/forecast"
            params = {
                'q': city,
                'appid': self.api_key,
                'units': units
            }
            
            response = requests.get(url, params=params)
            response.raise_for_status()
            
            data = response.json()
            forecast_list = []
            
            # Process forecast data (every 3 hours)
            for item in data['list'][:8]:  # Next 24 hours (8 * 3hr intervals)
                forecast_list.append({
                    'datetime': item['dt_txt'],
                    'temperature': item['main']['temp'],
                    'description': item['weather'][0]['description'],
                    'wind_speed': item['wind']['speed']
                })
            
            return {
                'city': city,
                'forecast': forecast_list
            }
            
        except requests.exceptions.RequestException as e:
            print(f"Error fetching forecast data: {e}")
            return None

# Example usage
if __name__ == "__main__":
    # You need to get a free API key from https://openweathermap.org/api
    API_KEY = "your_api_key_here"
    
    # Initialize the weather fetcher
    weather = WeatherFetcher(API_KEY)
    
    # Get current weather for a city
    city_name = "London"
    current_weather = weather.get_weather(city_name)
    
    if current_weather:
        print(f"\nCurrent Weather in {current_weather['city']}:")
        print(f"Temperature: {current_weather['temperature']}°C")
        print(f"Feels like: {current_weather['feels_like']}°C")
        print(f"Description: {current_weather['description'].title()}")
        print(f"Humidity: {current_weather['humidity']}%")
        print(f"Wind Speed: {current_weather['wind_speed']} m/s")
    
    # Get weather forecast
    forecast = weather.get_forecast(city_name)
    
    if forecast:
        print(f"\n24-Hour Forecast for {forecast['city']}:")
        for entry in forecast['forecast']:
            print(f"{entry['datetime']}: {entry['temperature']}°C, {entry['description'].title()}")

What This Code Does

This Python snippet creates a WeatherFetcher class that retrieves current weather conditions and forecasts from the OpenWeatherMap API. It includes intelligent caching to avoid unnecessary API calls and provides formatted weather data suitable for applications.

Key features:

Why This is Useful

Many applications need weather information but making constant API requests is inefficient and may exceed rate limits. This implementation:

  1. Reduces API usage through intelligent caching
  2. Handles authentication and request formatting
  3. Processes raw API data into clean, usable Python dictionaries
  4. Provides both current conditions and future forecasts
  5. Works with any location worldwide

How to Run It

  1. Get a free API key from OpenWeatherMap
  2. Replace "your_api_key_here" with your actual API key
  3. Install required dependencies: pip install requests
  4. Run the script directly or import the class into your project
  5. Call get_weather(city_name) for current conditions
  6. Call get_forecast(city_name) for future predictions

The caching feature automatically stores weather data for 1 hour (configurable) to minimize API calls while ensuring reasonably fresh information.