使用Python編寫一個每日天氣提醒
1. 引言
在這個快節(jié)奏的時代,一個小小的貼心舉動往往能帶來意想不到的溫暖。想象一下,每天清晨,你的女朋友都能收到一條溫馨的天氣提醒,不僅包含準確的天氣信息,還有你親自編寫的暖心提示——這樣的關懷是不是很讓人心動?
本文就將教你如何使用Python構建一個自動化的每日天氣提醒系統(tǒng)。這個系統(tǒng)不僅實用,更重要的是它融入了你的個人情感,讓技術變得有溫度。無論你是編程新手還是有經驗的開發(fā)者,都能通過本文學會如何將技術轉化為貼心的浪漫工具。
2. 系統(tǒng)設計與功能規(guī)劃
2.1 系統(tǒng)架構設計
在開始編碼之前,讓我們先來規(guī)劃整個系統(tǒng)的架構。我們的天氣提醒系統(tǒng)需要包含以下幾個核心模塊:

2.2 核心功能特性
我們的天氣提醒系統(tǒng)將實現以下特色功能:
- 精準天氣信息:獲取實時天氣、溫度、濕度、風速等詳細信息
- 智能穿衣建議:根據溫度自動生成合適的穿衣建議
- 個性化關懷提示:結合天氣情況提供貼心的生活建議
- 多平臺支持:支持微信、郵件、短信等多種發(fā)送方式
- 定時發(fā)送:在指定時間自動發(fā)送提醒
- 異常處理:網絡異?;蚍詹豢捎脮r的備用方案
2.3 技術選型
- 天氣數據源:使用和風天氣、OpenWeatherMap等免費API
- 消息發(fā)送:使用SMTP協(xié)議發(fā)送郵件,或itchat庫發(fā)送微信
- 定時任務:使用APScheduler庫管理定時任務
- 數據存儲:使用SQLite存儲配置和歷史記錄
- 配置管理:使用配置文件或環(huán)境變量管理敏感信息
3. 準備工作與環(huán)境配置
3.1 申請?zhí)鞖釧PI服務
首先,我們需要選擇一個天氣數據提供商。這里以和風天氣(免費版)為例:
- 訪問和風天氣官網注冊賬號
- 創(chuàng)建應用,獲取API Key
- 了解API調用方式和返回數據格式
其他可選天氣服務:
- OpenWeatherMap(免費版有限制)
- 心知天氣
- 阿里云天氣API
3.2 安裝必要的Python庫
pip install requests apscheduler python-dotenv sqlalchemy
如果需要微信支持,還需要安裝:
pip install itchat-uos
3.3 環(huán)境變量配置
創(chuàng)建.env文件來存儲敏感信息:
# 天氣API配置 WEATHER_API_KEY=你的和風天氣API_KEY WEATHER_CITY=北京 # 郵箱配置(用于發(fā)送郵件提醒) EMAIL_HOST=smtp.qq.com EMAIL_PORT=587 EMAIL_USER=你的郵箱@qq.com EMAIL_PASSWORD=你的郵箱授權碼 # 接收方配置 RECIPIENT_EMAIL=女朋友的郵箱@gmail.com RECIPIENT_NAME=親愛的
4. 核心模塊實現
4.1 天氣數據獲取模塊
import requests
import json
from datetime import datetime, timedelta
import logging
from typing import Dict, List, Optional
class WeatherService:
"""天氣服務類,負責獲取和處理天氣數據"""
def __init__(self, api_key: str, city: str):
"""
初始化天氣服務
Args:
api_key: 和風天氣API Key
city: 城市名稱
"""
self.api_key = api_key
self.city = city
self.base_url = "https://devapi.qweather.com/v7"
self.logger = logging.getLogger(__name__)
def get_city_location(self) -> Optional[Dict]:
"""獲取城市位置信息(城市ID、坐標等)"""
url = f"{self.base_url}/weather/now"
params = {
'location': self.city,
'key': self.api_key
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['code'] == '200':
# 從返回數據中提取位置信息
location_info = {
'city': data.get('location', [{}])[0].get('name', self.city),
'id': data.get('location', [{}])[0].get('id', ''),
'lat': data.get('location', [{}])[0].get('lat', ''),
'lon': data.get('location', [{}])[0].get('lon', '')
}
return location_info
else:
self.logger.error(f"獲取位置信息失敗: {data.get('message', '未知錯誤')}")
return None
except requests.exceptions.RequestException as e:
self.logger.error(f"網絡請求失敗: {str(e)}")
return None
except Exception as e:
self.logger.error(f"獲取位置信息異常: {str(e)}")
return None
def get_current_weather(self) -> Optional[Dict]:
"""獲取當前天氣情況"""
url = f"{self.base_url}/weather/now"
params = {
'location': self.city,
'key': self.api_key,
'lang': 'zh' # 中文返回
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['code'] == '200':
weather_data = data['now']
return {
'temp': weather_data.get('temp', 'N/A'), # 溫度
'feels_like': weather_data.get('feelsLike', 'N/A'), # 體感溫度
'text': weather_data.get('text', 'N/A'), # 天氣狀況文字
'wind_scale': weather_data.get('windScale', 'N/A'), # 風力等級
'wind_dir': weather_data.get('windDir', 'N/A'), # 風向
'humidity': weather_data.get('humidity', 'N/A'), # 濕度
'precip': weather_data.get('precip', '0'), # 降水量
'vis': weather_data.get('vis', 'N/A'), # 能見度
'pressure': weather_data.get('pressure', 'N/A'), # 氣壓
'update_time': weather_data.get('obsTime', '') # 更新時間
}
else:
self.logger.error(f"獲取當前天氣失敗: {data.get('message', '未知錯誤')}")
return None
except requests.exceptions.RequestException as e:
self.logger.error(f"獲取當前天氣網絡請求失敗: {str(e)}")
return None
except Exception as e:
self.logger.error(f"獲取當前天氣異常: {str(e)}")
return None
def get_daily_forecast(self, days: int = 3) -> Optional[List[Dict]]:
"""獲取多日天氣預報"""
url = f"{self.base_url}/weather/{days}d"
params = {
'location': self.city,
'key': self.api_key,
'lang': 'zh'
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['code'] == '200':
forecast_list = []
for day_data in data.get('daily', []):
forecast = {
'date': day_data.get('fxDate', ''),
'temp_max': day_data.get('tempMax', 'N/A'),
'temp_min': day_data.get('tempMin', 'N/A'),
'text_day': day_data.get('textDay', 'N/A'),
'text_night': day_data.get('textNight', 'N/A'),
'wind_scale_day': day_data.get('windScaleDay', 'N/A'),
'humidity': day_data.get('humidity', 'N/A'),
'precip': day_data.get('precip', '0'),
'uv_index': day_data.get('uvIndex', 'N/A')
}
forecast_list.append(forecast)
return forecast_list
else:
self.logger.error(f"獲取天氣預報失敗: {data.get('message', '未知錯誤')}")
return None
except requests.exceptions.RequestException as e:
self.logger.error(f"獲取天氣預報網絡請求失敗: {str(e)}")
return None
except Exception as e:
self.logger.error(f"獲取天氣預報異常: {str(e)}")
return None
def get_weather_warning(self) -> Optional[List[Dict]]:
"""獲取天氣預警信息"""
url = f"{self.base_url}/warning/now"
params = {
'location': self.city,
'key': self.api_key,
'lang': 'zh'
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['code'] == '200':
warnings = []
for warning in data.get('warning', []):
warning_info = {
'type': warning.get('type', ''),
'level': warning.get('level', ''),
'title': warning.get('title', ''),
'text': warning.get('text', '')
}
warnings.append(warning_info)
return warnings
else:
# 沒有預警信息是正常情況
return []
except Exception as e:
self.logger.warning(f"獲取天氣預警信息失敗: {str(e)}")
return []
4.2 智能分析與建議生成模塊
class WeatherAnalyzer:
"""天氣分析器,根據天氣數據生成智能建議"""
def __init__(self):
self.advice_templates = {
'dressing': self._get_dressing_advice,
'umbrella': self._get_umbrella_advice,
'outdoor': self._get_outdoor_advice,
'health': self._get_health_advice,
'travel': self._get_travel_advice
}
def analyze_temperature(self, temp: int) -> Dict[str, str]:
"""分析溫度并給出建議"""
temp = int(temp)
if temp >= 30:
level = "炎熱"
feeling = "今天天氣炎熱,注意防暑降溫"
elif temp >= 25:
level = "溫暖"
feeling = "今天天氣溫暖,適合戶外活動"
elif temp >= 15:
level = "舒適"
feeling = "今天天氣舒適,是出行的好日子"
elif temp >= 5:
level = "涼爽"
feeling = "今天天氣涼爽,記得適當添衣"
elif temp >= 0:
level = "寒冷"
feeling = "今天天氣寒冷,注意保暖"
else:
level = "嚴寒"
feeling = "今天天氣嚴寒,盡量減少外出"
return {'level': level, 'feeling': feeling}
def _get_dressing_advice(self, temp: int, weather_text: str) -> str:
"""生成穿衣建議"""
temp = int(temp)
if "雨" in weather_text:
rain_note = "有雨,建議穿防水的衣物"
else:
rain_note = ""
if temp >= 28:
return f"?? 輕薄夏裝(短袖、裙子){rain_note}"
elif temp >= 24:
return f"?? 夏季服裝(短袖、薄長褲){rain_note}"
elif temp >= 18:
return f"?? 春秋過渡裝(長袖T恤、薄外套){rain_note}"
elif temp >= 12:
return f"?? 春秋裝(長袖、薄毛衣、外套){rain_note}"
elif temp >= 6:
return f"?? 初冬裝(毛衣、厚外套){rain_note}"
elif temp >= 0:
return f"?? 冬裝(羽絨服、厚毛衣){rain_note}"
else:
return f"?? 厚冬裝(加厚羽絨服、保暖內衣){rain_note}"
def _get_umbrella_advice(self, weather_text: str, precip: float) -> str:
"""生成雨具建議"""
precip = float(precip)
if "雨" in weather_text or precip > 0:
if precip > 10:
return "?? 今天有大雨,一定要帶傘,建議穿雨鞋"
elif precip > 5:
return "? 今天有中雨,記得帶傘"
else:
return "??? 今天有小雨,建議帶傘"
else:
return "?? 今天無雨,可以不用帶傘"
def _get_outdoor_advice(self, weather_text: str, temp: int, wind_scale: str) -> str:
"""生成戶外活動建議"""
temp = int(temp)
advice = []
# 溫度適宜性
if 18 <= temp <= 26:
advice.append("今天的溫度非常適合戶外活動")
elif temp > 30:
advice.append("天氣炎熱,建議在陰涼處活動")
elif temp < 5:
advice.append("天氣較冷,戶外活動請注意保暖")
# 天氣狀況
if "晴" in weather_text:
advice.append("陽光很好,適合散步和運動")
elif "雨" in weather_text:
advice.append("有雨,建議室內活動")
elif "云" in weather_text:
advice.append("多云天氣,適合各種戶外活動")
elif "雪" in weather_text:
advice.append("下雪天,注意防滑")
# 風力影響
if int(wind_scale) >= 6:
advice.append("今天風較大,注意安全")
return "。".join(advice) if advice else "今天天氣平穩(wěn),按計劃活動即可"
def _get_health_advice(self, temp: int, humidity: int, uv_index: str) -> str:
"""生成健康建議"""
temp = int(temp)
humidity = int(humidity)
advice = []
# 溫度相關
if temp >= 30:
advice.append("天氣炎熱,注意補充水分,預防中暑")
elif temp <= 0:
advice.append("天氣寒冷,注意保暖,預防感冒")
# 濕度相關
if humidity >= 80:
advice.append("濕度較高,注意防潮")
elif humidity <= 30:
advice.append("空氣干燥,注意保濕")
# 紫外線
if uv_index in ['5', '6', '7']:
advice.append("紫外線中等,建議使用防曬霜")
elif uv_index in ['8', '9', '10']:
advice.append("紫外線強,需要做好防曬措施")
elif uv_index in ['11', '12', '13', '14', '15']:
advice.append("紫外線很強,盡量避免長時間在陽光下")
return "。".join(advice) if advice else "今天天氣條件對健康影響較小"
def _get_travel_advice(self, weather_text: str, vis: str) -> str:
"""生成出行建議"""
advice = []
if "雨" in weather_text:
advice.append("雨天路滑,開車請減速慢行")
elif "雪" in weather_text:
advice.append("雪天路滑,建議使用公共交通工具")
elif "霧" in weather_text:
advice.append("有霧,能見度較低,注意行車安全")
if vis and int(vis) < 1:
advice.append("能見度很低,出行請?zhí)貏e注意安全")
elif vis and int(vis) < 5:
advice.append("能見度一般,小心駕駛")
return "。".join(advice) if advice else "今天出行條件良好"
def generate_comprehensive_advice(self, weather_data: Dict) -> Dict[str, str]:
"""生成綜合建議"""
temp = int(weather_data.get('temp', 20))
weather_text = weather_data.get('text', '')
precip = float(weather_data.get('precip', 0))
wind_scale = weather_data.get('wind_scale', '1')
humidity = int(weather_data.get('humidity', 50))
uv_index = weather_data.get('uv_index', '3')
vis = weather_data.get('vis', '10')
return {
'temperature_analysis': self.analyze_temperature(temp),
'dressing': self._get_dressing_advice(temp, weather_text),
'umbrella': self._get_umbrella_advice(weather_text, precip),
'outdoor': self._get_outdoor_advice(weather_text, temp, wind_scale),
'health': self._get_health_advice(temp, humidity, uv_index),
'travel': self._get_travel_advice(weather_text, vis)
}
4.3 個性化消息生成模塊
import random
from datetime import datetime
class MessageGenerator:
"""消息生成器,創(chuàng)建個性化的天氣提醒消息"""
def __init__(self, recipient_name: str):
self.recipient_name = recipient_name
self.greetings = [
"早安,{}!新的一天開始啦",
"早上好,{}!愿你有美好的一天",
"{},醒來了嗎?來看看今天的天氣吧",
"嗨,{}!今天也要加油哦",
"{},新的一天充滿新的可能"
]
self.closing_remarks = [
"記得按時吃飯,愛你??",
"不管天氣如何,我的關心永遠不變??",
"今天也要開開心心的哦??",
"記得想我,就像我想你一樣??",
"愿你的一天像陽光一樣燦爛?"
]
self.special_date_remarks = {
'anniversary': "今天是我們的紀念日,晚上有驚喜哦??",
'birthday': "生日快樂!我的小公主??",
'valentine': "情人節(jié)快樂!我的愛人??",
'weekend': "周末愉快!我們出去約會吧??"
}
def _check_special_date(self) -> Optional[str]:
"""檢查是否是特殊日期"""
today = datetime.now()
# 這里可以添加你們的特殊日期
special_dates = {
# 'anniversary': datetime(2024, 2, 14), # 紀念日示例
# 'birthday': datetime(2024, 3, 8), # 生日示例
}
for occasion, date in special_dates.items():
if today.month == date.month and today.day == date.day:
return occasion
# 檢查周末
if today.weekday() >= 5: # 5=周六, 6=周日
return 'weekend'
return None
def generate_message(self, weather_data: Dict, advice_data: Dict,
forecast_data: List[Dict] = None) -> str:
"""生成完整的天氣提醒消息"""
# 問候語
greeting = random.choice(self.greetings).format(self.recipient_name)
# 當前天氣摘要
current_temp = weather_data.get('temp', 'N/A')
weather_text = weather_data.get('text', 'N/A')
temp_analysis = advice_data['temperature_analysis']
weather_summary = (
f"??? 當前溫度:{current_temp}°C({temp_analysis['level']})\n"
f"??? 天氣狀況:{weather_text}\n"
f"?? 體感溫度:{weather_data.get('feels_like', 'N/A')}°C\n"
f"?? 濕度:{weather_data.get('humidity', 'N/A')}%\n"
f"??? 風力:{weather_data.get('wind_scale', 'N/A')}級 {weather_data.get('wind_dir', '')}"
)
# 生活建議
advice_section = (
f"\n?? 今日生活建議:\n"
f"{advice_data['dressing']}\n"
f"{advice_data['umbrella']}\n"
f"{advice_data['outdoor']}\n"
f"{advice_data['health']}\n"
f"{advice_data['travel']}"
)
# 天氣預報
forecast_section = ""
if forecast_data:
forecast_section = "\n\n?? 未來三天預報:\n"
for i, forecast in enumerate(forecast_data[:3]):
date_str = forecast['date'][5:] # 只顯示月日
day_name = "今天" if i == 0 else "明天" if i == 1 else "后天"
forecast_section += (
f"{day_name}({date_str}):{forecast['text_day']},"
f"{forecast['temp_min']}~{forecast['temp_max']}°C\n"
)
# 預警信息
warning_section = ""
warnings = weather_data.get('warnings', [])
if warnings:
warning_section = "\n?? 天氣預警:\n"
for warning in warnings:
warning_section += f"{warning['title']}:{warning['text']}\n"
# 特殊日期備注
special_remark = ""
special_occasion = self._check_special_date()
if special_occasion:
special_remark = f"\n?? {self.special_date_remarks[special_occasion]}"
# 結束語
closing = random.choice(self.closing_remarks)
# 組合所有部分
full_message = (
f"{greeting}\n\n"
f"{weather_summary}"
f"{advice_section}"
f"{forecast_section}"
f"{warning_section}"
f"{special_remark}\n\n"
f"{closing}"
)
return full_message
def generate_html_message(self, weather_data: Dict, advice_data: Dict,
forecast_data: List[Dict] = None) -> str:
"""生成HTML格式的消息(用于郵件)"""
# 這里實現HTML格式的消息生成
# 由于篇幅限制,具體實現略
pass
4.4 消息發(fā)送模塊
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import logging
from typing import List
class MessageSender:
"""消息發(fā)送器,支持多種發(fā)送方式"""
def __init__(self):
self.logger = logging.getLogger(__name__)
def send_email(self, recipient: str, subject: str, content: str,
smtp_host: str, smtp_port: int,
username: str, password: str) -> bool:
"""通過郵件發(fā)送消息"""
try:
# 創(chuàng)建郵件對象
msg = MIMEMultipart()
msg['From'] = username
msg['To'] = recipient
msg['Subject'] = subject
# 添加文本內容
text_part = MIMEText(content, 'plain', 'utf-8')
msg.attach(text_part)
# 發(fā)送郵件
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls() # 啟用TLS加密
server.login(username, password)
server.send_message(msg)
self.logger.info(f"郵件發(fā)送成功:{recipient}")
return True
except Exception as e:
self.logger.error(f"郵件發(fā)送失?。簕str(e)}")
return False
def send_wechat(self, content: str) -> bool:
"""通過微信發(fā)送消息(需要安裝itchat-uos)"""
try:
import itchat
# 查找指定備注的好友
friends = itchat.search_friends(name='女朋友的備注名') # 修改為實際備注
if friends:
friend = friends[0]
itchat.send(content, toUserName=friend['UserName'])
self.logger.info("微信消息發(fā)送成功")
return True
else:
self.logger.error("未找到指定的微信好友")
return False
except ImportError:
self.logger.error("未安裝itchat-uos,無法發(fā)送微信消息")
return False
except Exception as e:
self.logger.error(f"微信消息發(fā)送失?。簕str(e)}")
return False
def send_sms(self, phone_number: str, content: str,
api_key: str = None) -> bool:
"""通過短信API發(fā)送消息"""
# 這里可以實現短信發(fā)送功能
# 需要接入短信服務商API
self.logger.info("短信發(fā)送功能需要接入短信服務商API")
return False
def send_multiple_ways(self, content: str, config: Dict) -> bool:
"""嘗試多種方式發(fā)送消息"""
success = False
# 嘗試郵件發(fā)送
if config.get('email_enabled', False):
success = self.send_email(
recipient=config['recipient_email'],
subject=config.get('email_subject', '每日天氣提醒'),
content=content,
smtp_host=config['smtp_host'],
smtp_port=config['smtp_port'],
username=config['email_username'],
password=config['email_password']
)
# 如果郵件發(fā)送失敗,嘗試微信
if not success and config.get('wechat_enabled', False):
success = self.send_wechat(content)
return success
5. 系統(tǒng)集成與完整實現
現在我們將所有模塊整合在一起,創(chuàng)建一個完整的天氣提醒系統(tǒng):
#!/usr/bin/env python3
"""
每日天氣提醒系統(tǒng)
為你的女朋友提供貼心的天氣提醒服務
日期:2024年1月
"""
import os
import logging
from datetime import datetime
from dotenv import load_dotenv
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
import sqlite3
from typing import Dict, Any
# 導入自定義模塊
from weather_service import WeatherService
from weather_analyzer import WeatherAnalyzer
from message_generator import MessageGenerator
from message_sender import MessageSender
# 加載環(huán)境變量
load_dotenv()
class DailyWeatherReminder:
"""每日天氣提醒系統(tǒng)主類"""
def __init__(self, config: Dict[str, Any] = None):
"""初始化系統(tǒng)"""
# 配置日志
self._setup_logging()
# 加載配置
self.config = config or self._load_config()
# 初始化組件
self.weather_service = WeatherService(
api_key=self.config['weather_api_key'],
city=self.config['city']
)
self.weather_analyzer = WeatherAnalyzer()
self.message_generator = MessageGenerator(
recipient_name=self.config['recipient_name']
)
self.message_sender = MessageSender()
# 初始化數據庫
self._init_database()
# 初始化調度器
self.scheduler = BackgroundScheduler()
self.logger.info("每日天氣提醒系統(tǒng)初始化完成")
def _setup_logging(self):
"""配置日志系統(tǒng)"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('weather_reminder.log'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def _load_config(self) -> Dict[str, Any]:
"""從環(huán)境變量加載配置"""
return {
'weather_api_key': os.getenv('WEATHER_API_KEY'),
'city': os.getenv('WEATHER_CITY', '北京'),
'smtp_host': os.getenv('EMAIL_HOST'),
'smtp_port': int(os.getenv('EMAIL_PORT', 587)),
'email_username': os.getenv('EMAIL_USER'),
'email_password': os.getenv('EMAIL_PASSWORD'),
'recipient_email': os.getenv('RECIPIENT_EMAIL'),
'recipient_name': os.getenv('RECIPIENT_NAME', '親愛的'),
'send_time': os.getenv('SEND_TIME', '07:30'), # 默認早上7:30發(fā)送
'email_enabled': True,
'wechat_enabled': False
}
def _init_database(self):
"""初始化SQLite數據庫"""
self.conn = sqlite3.connect('weather_reminder.db', check_same_thread=False)
cursor = self.conn.cursor()
# 創(chuàng)建發(fā)送記錄表
cursor.execute('''
CREATE TABLE IF NOT EXISTS send_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
send_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
success BOOLEAN,
message TEXT,
weather_data TEXT
)
''')
self.conn.commit()
def _log_send_attempt(self, success: bool, message: str, weather_data: Dict):
"""記錄發(fā)送嘗試"""
cursor = self.conn.cursor()
cursor.execute(
'INSERT INTO send_history (success, message, weather_data) VALUES (?, ?, ?)',
(success, message, str(weather_data))
)
self.conn.commit()
def get_weather_data(self) -> Dict[str, Any]:
"""獲取完整的天氣數據"""
self.logger.info("開始獲取天氣數據...")
weather_data = {}
# 獲取當前天氣
current_weather = self.weather_service.get_current_weather()
if current_weather:
weather_data.update(current_weather)
else:
self.logger.error("獲取當前天氣數據失敗")
return {}
# 獲取天氣預報
forecast = self.weather_service.get_daily_forecast(days=3)
if forecast:
weather_data['forecast'] = forecast
else:
self.logger.warning("獲取天氣預報數據失敗")
# 獲取天氣預警
warnings = self.weather_service.get_weather_warning()
if warnings:
weather_data['warnings'] = warnings
self.logger.info("天氣數據獲取完成")
return weather_data
def generate_weather_report(self) -> str:
"""生成完整的天氣報告"""
try:
# 獲取天氣數據
weather_data = self.get_weather_data()
if not weather_data:
return "抱歉,今天無法獲取天氣信息。請手動查看天氣哦~"
# 生成智能建議
advice_data = self.weather_analyzer.generate_comprehensive_advice(weather_data)
# 生成個性化消息
forecast_data = weather_data.get('forecast', [])
message = self.message_generator.generate_message(
weather_data, advice_data, forecast_data
)
return message
except Exception as e:
self.logger.error(f"生成天氣報告時發(fā)生錯誤: {str(e)}")
return f"今天天氣服務出了點小問題,但我的關心不會變~記得查看天氣哦!"
def send_daily_reminder(self):
"""發(fā)送每日提醒(主函數)"""
self.logger.info("開始發(fā)送每日天氣提醒...")
try:
# 生成天氣報告
message = self.generate_weather_report()
# 發(fā)送消息
success = self.message_sender.send_multiple_ways(message, self.config)
# 記錄發(fā)送結果
weather_data = self.get_weather_data() # 重新獲取用于記錄
self._log_send_attempt(success, message, weather_data)
if success:
self.logger.info("每日天氣提醒發(fā)送成功")
else:
self.logger.error("所有發(fā)送方式均失敗")
return success
except Exception as e:
self.logger.error(f"發(fā)送每日提醒時發(fā)生錯誤: {str(e)}")
self._log_send_attempt(False, f"Error: {str(e)}", {})
return False
def setup_schedule(self):
"""設置定時任務"""
# 解析發(fā)送時間
hour, minute = map(int, self.config['send_time'].split(':'))
# 添加每日定時任務
self.scheduler.add_job(
self.send_daily_reminder,
trigger=CronTrigger(hour=hour, minute=minute),
id='daily_weather_reminder',
name='每日天氣提醒',
replace_existing=True
)
self.logger.info(f"已設置每日 {hour:02d}:{minute:02d} 發(fā)送天氣提醒")
def send_test_message(self):
"""發(fā)送測試消息"""
self.logger.info("發(fā)送測試消息...")
return self.send_daily_reminder()
def start(self):
"""啟動系統(tǒng)"""
try:
# 設置定時任務
self.setup_schedule()
# 啟動調度器
self.scheduler.start()
self.logger.info("天氣提醒系統(tǒng)已啟動")
# 立即發(fā)送一次測試消息
self.send_test_message()
# 保持程序運行
try:
while True:
# 主線程可以在這里執(zhí)行其他任務
# 或者簡單地等待
import time
time.sleep(60)
except KeyboardInterrupt:
self.logger.info("收到中斷信號,正在關閉系統(tǒng)...")
except Exception as e:
self.logger.error(f"啟動系統(tǒng)時發(fā)生錯誤: {str(e)}")
finally:
self.shutdown()
def shutdown(self):
"""關閉系統(tǒng)"""
if hasattr(self, 'scheduler') and self.scheduler.running:
self.scheduler.shutdown()
if hasattr(self, 'conn'):
self.conn.close()
self.logger.info("天氣提醒系統(tǒng)已關閉")
def main():
"""主函數"""
# 可以在這里覆蓋默認配置
custom_config = {
'city': '上海', # 修改為女朋友所在城市
'send_time': '08:00', # 修改為合適的發(fā)送時間
# 添加其他自定義配置...
}
# 創(chuàng)建并啟動系統(tǒng)
reminder_system = DailyWeatherReminder(custom_config)
reminder_system.start()
if __name__ == "__main__":
main()
6. 部署與運行
6.1 本地運行
創(chuàng)建項目目錄結構:
weather_reminder/
├── main.py
├── weather_service.py
├── weather_analyzer.py
├── message_generator.py
├── message_sender.py
├── .env
├── requirements.txt
└── config.json (可選)
安裝依賴:
pip install -r requirements.txt
配置環(huán)境變量(.env文件):
WEATHER_API_KEY=你的和風天氣API_KEY WEATHER_CITY=北京 EMAIL_HOST=smtp.qq.com EMAIL_PORT=587 EMAIL_USER=你的QQ郵箱 EMAIL_PASSWORD=QQ郵箱授權碼 RECIPIENT_EMAIL=女朋友的郵箱 RECIPIENT_NAME=親愛的 SEND_TIME=07:30
運行系統(tǒng):
python main.py
6.2 服務器部署
對于24小時運行,建議部署到云服務器:
使用systemd服務(Linux):創(chuàng)建/etc/systemd/system/weather-reminder.service:
[Unit] Description=Daily Weather Reminder After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/path/to/weather_reminder ExecStart=/usr/bin/python3 main.py Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
使用Docker部署:
創(chuàng)建Dockerfile:
FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["python", "main.py"]
6.3 微信版本特別說明
如果要使用微信版本,需要注意:
安裝itchat-uos(解決微信網頁版登錄問題):
pip install itchat-uos
修改代碼使用微信發(fā)送:
# 在message_sender中啟用微信發(fā)送
def send_wechat_message(self, content: str) -> bool:
import itchat
# 自動登錄(會彈出二維碼)
itchat.auto_login(hotReload=True, enableCmdQR=2)
# 發(fā)送給文件傳輸助手(測試用)
itchat.send(content, toUserName='filehelper')
# 或者發(fā)送給指定好友
friends = itchat.search_friends(name='女朋友的微信昵稱')
if friends:
itchat.send(content, toUserName=friends[0]['UserName'])
itchat.logout()
return True
7. 個性化定制建議
7.1 添加特殊日期提醒
在MessageGenerator類中添加你們的特殊日期:
special_dates = {
'anniversary': datetime(2024, 5, 20), # 紀念日
'birthday': datetime(2024, 8, 15), # 生日
'valentine': datetime(2024, 2, 14), # 情人節(jié)
'first_meet': datetime(2024, 3, 8) # 初次見面日
}
7.2 自定義關懷語句
豐富問候語和結束語庫:
self.greetings = [
"早安,我的小太陽{}!",
"{}寶貝,新的一天開始啦",
"嘿,{}!今天也是愛你的一天",
"早上好,{}!你是我今天第一個想念的人"
]
self.closing_remarks = [
"記得按時吃飯,你胃不好~",
"今天也要想我一千遍哦",
"工作再忙也要記得休息,心疼你",
"晚上視頻哦,想你??"
]
7.3 天氣相關的情話
根據天氣添加不同的情話:
def get_weather_pickup_line(self, weather_text: str) -> str:
"""根據天氣生成情話"""
lines = {
'晴': "今天的陽光和你一樣溫暖我的心",
'雨': "雨水可以打濕街道,但打不濕我想你的心",
'云': "云朵遮住了太陽,但遮不住我對你的思念",
'雪': "雪花飄落的時候,我在想你有沒有穿暖",
'風': "風兒吹過,帶去我對你的牽掛"
}
for key, line in lines.items():
if key in weather_text:
return line
return "無論什么天氣,你都是我的晴天"
8. 故障排除與優(yōu)化
8.1 常見問題解決
問題1:API調用失敗
- 檢查API Key是否正確
- 確認網絡連接正常
- 查看天氣服務商的服務狀態(tài)
問題2:郵件發(fā)送失敗
- 檢查郵箱授權碼(不是登錄密碼)
- 確認SMTP服務器地址和端口正確
- 檢查防火墻設置
問題3:定時任務不執(zhí)行
- 確認系統(tǒng)時間正確
- 檢查調度器是否正常啟動
- 查看日志文件排查錯誤
8.2 性能優(yōu)化建議
緩存城市信息:避免重復查詢城市位置
錯誤重試機制:網絡請求失敗時自動重試
備用數據源:準備多個天氣API備用
消息隊列:使用Redis等管理發(fā)送任務
8.3 監(jiān)控與維護
- 日志監(jiān)控:定期檢查系統(tǒng)日志
- API使用量:監(jiān)控天氣API調用次數
- 發(fā)送成功率:統(tǒng)計消息發(fā)送成功率
- 定期備份:備份配置和發(fā)送記錄
9. 完整代碼文件
由于完整的代碼較長,這里提供各模塊的文件劃分:
9.1 requirements.txt
requests>=2.28.0 apscheduler>=3.9.0 python-dotenv>=0.19.0 python-dateutil>=2.8.0 itchat-uos>=1.5.0
9.2 weather_service.py
(包含WeatherService類,詳見第4.1節(jié))
9.3 weather_analyzer.py
(包含WeatherAnalyzer類,詳見第4.2節(jié))
9.4 message_generator.py
(包含MessageGenerator類,詳見第4.3節(jié))
9.5 message_sender.py
(包含MessageSender類,詳見第4.4節(jié))
9.6 main.py
(包含DailyWeatherReminder主類,詳見第5節(jié))
10. 總結
通過本文的指導,你已經學會了如何使用Python構建一個功能完整、貼心實用的每日天氣提醒系統(tǒng)。這個系統(tǒng)不僅技術上有價值,更重要的是它承載了你的情感和關懷。
10.1 技術收獲
- 掌握了API調用的最佳實踐
- 學會了構建模塊化的Python應用
- 了解了定時任務的實現方式
- 掌握了異常處理和日志記錄
10.2 情感價值
這個天氣提醒系統(tǒng)的真正價值在于:
- 持續(xù)關懷:每天準時的提醒體現持續(xù)的關注
- 個性化:根據天氣提供的建議展現細心和體貼
- 實用性:真實的天氣信息幫助日常生活
- 驚喜感:特殊日子的特別提醒增加浪漫氛圍
10.3 擴展思路
你可以進一步擴展這個系統(tǒng):
- 添加更多消息平臺(釘釘、飛書等)
- 集成日歷系統(tǒng),提醒重要日程
- 添加機器學習,學習女朋友的偏好
- 開發(fā)手機APP,提供更好的交互體驗
記住,技術只是工具,真正打動人心的永遠是你的用心和關懷。希望這個天氣提醒系統(tǒng)能為你們的感情增添一份科技的溫暖!
溫馨提示:在使用過程中,請尊重女朋友的隱私和偏好,確保她喜歡這樣的關懷方式。技術應該服務于感情,而不是替代真實的交流和相處。祝你們的感情像精心編寫的代碼一樣,穩(wěn)定而美好!
以上就是使用Python編寫一個每日天氣提醒的詳細內容,更多關于Python每日天氣提醒的資料請關注腳本之家其它相關文章!

