使用Python编写一个每日天气提醒
目录
- 1. 引言
- 2. 系统设计与功能规划
- 2.1 系统架构设计
- 2.2 核心功能特性
- 2.3 技术选型
- 3. 准备工作与环境配置
- 3.1 申请天气API服务
- 3.2 安装必要的python库
- 3.3 环境变量配置
- 4. 核心模块实现
- 4.1 天气数据获取模块
- 4.2 智能分析与建议生成模块
- 4.3 个性化消息生成模块
- 4.4 消息发送模块
- 5. 系统集成与完整实现
- 6. 部署与运行
- 6.1 本地运行
- 6.2 服务器部署
- 6.3 微信版本特别说明
- 7. 个性化定制建议
- 7.1 添加特殊日期提醒
- 7.2 自定义关怀语句
- 7.3 天气相关的情话
- 8. 故障排除与优化
- 8.1 常见问题解决
- 8.2 性能优化建议
- 8.3 监控与维护
- 9. 完整代码文件
- 9.1 requirements.txt
- 9.2 weather_service.py
- 9.3 weather_analyzer.py
- 9.4 message_generator.py
- 9.5 message_sender.py
- 9.6 main.py
- 10. 总结
- 10.1 技术收获
- 10.2 情感价值
- 10.3 扩展思路
1. 引言
在这个快节奏的时代,一个小小的贴心举动往往能带来意想不到的温暖。想象一下,每天清晨,你的女朋友都能收到一条温馨的天气提醒,不仅包含准确的天气信息,还有你亲自编写的暖心提示——这样的关怀是不是很让人心动?
本文就将教你如何使用Python构建一个自动化的每日天气提醒系统。这个系统不仅实用,更重要的是它融入了你的个人情感,让技术变得有温度。无论你是编程新手还是有经验的开发者,都能通过本文学会如何将技术转化为贴心的浪漫工具。
2. 系统设计与功能规划
2.1 系统架构设计
在开始编码之前,让我们先来规划整个系统的架构。我们的天气提醒系统需要包含以下几个核心模块:

2.2 核心功能特性
我们的天气提醒系统将实现以下特色功能:
- 精准天气信息:获取实时天气、温度、湿度、风速等详细信息
- 智能穿衣建议:根据温度自动生成合适的穿衣建议
- 个性化关怀提示:结合天气情况提供贴心的生活建议
- 多平台支持:支持微信、邮件、短信等多种发送方式
- 定时发送:在指定时间自动发送提醒
- 异常处理:网络异常或服务不可用时的备用方案
2.3 技术选型
- 天气数据源:使用和风天气、OpenWeatherMap等免费API
- 消息发送:使用SMTP协议发送邮件,或itchat库发送微信
- 定时任务:使用APScheduler库管理定时任务
- 数据存储:使用SQLite存储配置和历史记录
- 配置管理:使用配置文件或环境变量管理敏感信息
3. 准备工作与环境配置
3.1 申请天气API服务
首先,我们需要选择一个天气数据提供商。这里以和风天气(免费版)为例:
- 访问和风天气官网注册账号
- 创建应用,获取API Key
- 了解API调用方式和返回数据格式
其他可选天气服务:
- OpenWeatherMap(免费版有限制)
- 心知天气
- 阿里云天气API
3.2 安装必要的Python库
pip install requests apscheduler python-dotenv sqlalchemy
如果需要微信支持,还需要安装:
pip install itchat-uos
3.3 环境变量配置
创建.env文件来存储敏感信息:
# 天气API配置 WEATHER_API_KEY=你的和风天气API_KEY WEATHER_CITY=北京 # 邮箱配置(用于发送邮件提醒) 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:
phpself.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 "今天天气平稳,按计划活动即可"
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("能见度很低,出行请特别注意安全")
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:
"""消息生成器,创建个性化的天气提醒消息"""
def __init__(self, recipient_name: str):
self.recipient_name = recipient_name
self.greetings = [
"早安,{}!新的一天开始啦",
"早上好,{}!愿你有美好的一天",
"{},醒来了吗?来看看今天的天气吧",
"嗨,{}!今天也要加油哦",
"{},新的一天充满新的可能"
]
self.closing_remarks = [
"记得按时吃饭,爱你❤️",
"不管天气如何,我的关心永远不变",
"今天也要开开心心的哦",
"记得想我,就像我想你一样",
"愿你的一天像阳光一样灿烂✨"
]
self.special_date_remarks = {
'anniversary': "今天是我们的纪念日,晚上有惊喜哦",
'birthday': "生日快乐!我的小公主",
'valentine': "情人节快乐!我的爱人",
'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,
OGxAmZh 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 消息发送模块
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import logging
from typing import List
class MessageSender:
"""消息发送器,支持多种发送方式"""
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:
"""通过邮件发送消息"""
try:
# 创建邮件对象
msg = MIMEMultipart()
msg['From'] = username
msg['To'] = recipient
msg['Subject'] = subject
# 添加文本内容
text_part = MIMEText(content, 'plain', 'utf-8')
msg.attach(text_part)
# 发送邮件
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls() # 启用TLS加密
server.login(username, password)
server.send_message(msg)
self.logger.info(f"邮件发送成功:{recipient}")
return True
except Exception as e:
self.logger.error(f"邮件发送失败:{str(e)}")
return False
def send_wechat(self, content: str) -> bool:
"""通过微信发送消息(需要安装itchat-uos)"""
try:
import itchat
# 查找指定备注的好友
friends = itchat.search_friends(name='女朋友的备注名') # 修改为实际备注
if friends:
friend = friends[0]
itchat.send(content, toUserName=friend['UserName'])
self.logger.info("微信消息发送成功")
return True
else:
self.logger.error("未找到指定的微信好友")
return False
except ImportError:
self.logger.error("未安装itchat-uos,无法发送微信消息")
return False
except Exception as e:
self.logger.error(f"微信消息发送失败:{str(e)}")
return False
def send_sms(self, phone_number: str, content: str,
api_key: str = None) -> bool:
"""通过短信API发送消息"""
# 这里可以实现短信发送功能
# 需要接入短信服务商API
self.logger.info("短信发送功能需要接入短信服务商API")
return False
def send_multiple_ways(self, content: str, config: Dict) -> bool:
"""尝试多种方式发送消息"""
success = False
# 尝试邮件发送
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']
)
# 如果邮件发送失败,尝试微信
if not success and config.get('wechat_enabled', False):
success = self.send_wechat(content)
return success
5. 系统集成与完整实现
现在我们将所有模块整合在一起,创建一个完整的天气提醒系统:
#!/usr/bin/env python3
"""
每日天气提醒系统
为你的女朋友提供贴心的天气提醒服务
日期: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
# 加载环境变量
load_dotenv()
class DailyWeatherReminder:
"""每日天气提醒系统主类"""
def __init__(self, config: Dict[str, Any] = None):
"""初始化系统"""
# 配置日志
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("每日天气提醒系统初始化完成")
def _setup_logging(self):
"""配置日志系统"""
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]:
"""从环境变量加载配置"""
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发送
'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()
# 创建发送记录表
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):
"""记录发送尝试"""
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"生成天气报告时发生错误: {str(e)}")
return f"今天天气服务出了点小问题,但我的关心不会变~记得查看天气哦!"
def send_daily_reminder(self):
"""发送每日提醒(主函数)"""
self.logger.info("开始发送每日天气提醒...")
try:
# 生成天气报告
message = self.generate_weather_report()
# 发送消息
success = self.message_sender.send_multiple_ways(message, self.config)
# 记录发送结果
weather_data = self.get_weather_data() # 重新获取用于记录
self._log_send_attempt(success, message, weather_data)
if success:
self.logger.info("每日天气提醒发送成功")
else:
self.logger.error("所有发送方式均失败")
return success
except Exception as e:
self.logger.error(f"发送每日提醒时发生错误: {str(e)}")
self._log_send_attempt(False, f"Error: {str(e)}", {})
return False
def setup_schedule(self):
"""设置定时任务"""
# 解析发送时间
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} 发送天气提醒")
def send_test_message(self):
"""发送测试消息"""
self.logger.info("发送测试消息...")
return self.send_daily_reminder()
def start(self):
"""启动系统"""
try:
# 设置定时任务
self.setup_schedule()
# 启动调度器
self.scheduler.start()
self.logger.info("天气提醒系统已启动")
# 立即发送一次测试消息
self.send_test_message()
# 保持程序运行
try:
while True:
# 主线程可以在这里执行其他任务
# 或者简单地等待
import time
time.sleep(60)
except KeyboardInterrupt:
self.logger.info("收到中断信号,正在关闭系统...")
except Exception as e:
self.logger.error(f"启动系统时发生错误: {str(e)}")
finally:
self.s编程客栈hutdown()
def shutdown(self):
"""关闭系统"""
if hasattr(self, 'scheduler') and self.scheduler.running:
self.scheduler.shutdown()
if hasattr(self, 'conn'):
self.conn.close()
self.logger.info("天气提醒系统已关闭")
def main():
"""主函数"""
# 可以在这里覆盖默认配置
custom_config = {
'city': '上海', # 修改为女朋友所在城市
'send_time': '08:00', # 修改为合适的发送时间
# 添加其他自定义配置...
}
# 创建并启动系统
reminder_system = DailyWeatherReminder(custom_config)
reminder_system.start()
if __name__ == "__main__":
main()
6. 部署与运行
6.1 本地运行
创建项目目录结构:
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
配置环境变量(.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
运行系统:
python main.py
6.2 服务器部署
对于24小时运行,建议部署到云服务器:
使用systemd服务(linux):创建/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部署:
创建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
修改代码使用微信发送:
# 在messagphpe_sender中启用微信发送
def send_wechat_message(self, content: str) -> bool:
import itchat
# 自动登录(会弹出二维码)
itchat.auto_login(hotReload=True, enableCmdQR=2)
# 发送给文件传输助手(测试用)
itchat.send(content, toUserName='filehelper')
# 或者发送给指定好友
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), # 情人节
'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. 故障排除与优化
8.1 常见问题解决
问题1:API调用失败
- 检查API Key是否正确
- 确认网络连接正常
- 查看天气服务商的服务状态
问题2:邮件发送失败
- 检查邮箱授权码(不是登录密码)
- 确认SMTP服务器地址和端口正确
- 检查防火墙设置
问题3:定时任务不执行
- 确认系统时间正确
- 检查调度器是否正常启动
- 查看日志文件排查错误
8.2 性能优化建议
缓存城市信息:避免重复查询城市位置
错误重试机制:网络请求失败时自动重试
备用数据源:准备多个天气API备用
消息队列:使用Redis等管理发送任务
8.3 监控与维护
- 日志监控:定期检查系统日志
- API使用量:监控天气API调用次数
- 发送成功率:统计消息发送成功率
- 定期备份:备份配置和发送记录
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节)
9.3 weather_analyzer.py
(包含WeatherAnalyzer类,详见第4.2节)
9.4 message_generator.py
(包含MessageGenerator类,详见第4.3节)
9.5 message_sender.py
(包含MessageSender类,详见第4.4节)
9.6 main.py
(包含DailyWeatherReminder主类,详见第5节)
10. 总结
通过本文的指导,你已经学会了如何使用Python构建一个功能完整、贴心实用的每日天气提醒系统。这个系统不仅技术上有价值,更重要的是它承载了你的情感和关怀。
10.1 技术收获
- 掌握了API调用的最佳实践
- 学会了构建模块化的Python应用
- 了解了定时任务的实现方式
- 掌握了异常处理和日志记录
10.2 情感价值
这个天气提醒系统的真正价值在于:
- 持续关怀:每天准时的提醒体现持续的关注
- 个性化:根据天气提供的建议展现细心和体贴
- 实用性:真实的天气信息帮助日常生活
- 惊喜感:特殊日子的特别提醒增加浪漫氛围
10.3 扩展思路
你可以进一步扩展这个系统:
- 添加更多消息平台(钉钉、飞书等)
- 集成日历系统,提醒重要日程
- 添加机器学习,学习女朋友的偏好
- 开发手机APP,提供更好的交互体验
记住,技术只是工具,真正打动人心的永远是你的用心和关怀。希望这个天气提醒系统能为你们的感情增添一份科技的温暖!
温馨提示:在使用过程中,请尊重女朋友的隐私和偏好,确保她喜欢这样的关怀方式。技术应该服务于感情,而不是替代真实的交流和相处。祝你们的感情像精心编写的代码一样,稳定而美好!
以上就是使用Python编写一个每日天气提醒的详细内容,更多关于Python每日天气提醒的资料请关注编程客栈(www.devze.com)其它相关文章!
加载中,请稍侯......
精彩评论