无遗漏之虞

-
-
2024-11-28

项目背景

自动发送邮件是一个很有用的技能,可以为我们的生活带来极大的便利——比如每周的周报写好之后,定时发送给mentor和boss;比如想要第一时间知道某网站的资讯,但是又不想频繁访问网站;比如天气预报有雨雪天气,想睡醒就收到预警;比如发送服务器当天的运行日志,便于晚上查看等等……以上都可以通过自动发送邮件给自己或他人完成,下面做其中一个演示:如果当天天气预报有雨雪等恶劣天气,则发送邮件预警。

需求分析

  1. 获取天气预报:获取第二天的天气预报,可通过天气API接口实现。
  2. 筛选天气条件:筛选出恶劣天气,如果是恶劣天气,才发送邮件预警。
  3. 定时:每天早上定时执行程序。
  4. 发送邮件:将邮件发送到指定邮箱,使用SMTP模块发送邮件。

实现步骤

  1. 获取天气预报:选择和风天气API,网站配备了详尽的开发文档可供查阅。

    import requests
    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    import json
    
    # 获取天气数据
    def get_weather_forecast(api_key, location):
        url = f'https://devapi.qweather.com/v7/weather/3d?location={location}&key={api_key}'
        data = requests.get(url).json()
        result = data['daily'][0]
        # 可通过GeoAPI查询,例如:curl --compressed "https://geoapi.qweather.com/v2/city/lookup?location=tokyo&key="
        city_name_map = { 
            "101060101": "长春",  
            "101280601": "深圳", 
            # "locationID": "city_name"
        }
        city_name = city_name_map.get(location, "未知城市")  # 默认值为 "未知城市"
        content = (
            f"城市:{city_name} \n"  # 动态插入城市名称
            f"日期: {result['fxDate']}\n"
            f"气温: {result['tempMin']}°C~{result['tempMax']}°C\n"
            f"日间天气: {result['textDay']}\n"
            f"晚间天气: {result['textNight']}\n"
            f"日出: {result['sunrise']}  日落: {result['sunset']}\n"
            f"预报当天总降水量: {result['precip']}mm\n"
            f"出门记得带伞,路上记得小心!\n"
        )
        return content
    
  2. 筛选天气:只有出现恶劣天气的时候才启动邮件发送。

    # 判断是否是坏天气
    def is_bad_weather(result):
        bad_weather_con = ["雨", "雪", "雷"]
        if any(weather in result['textDay'] for weather in bad_weather_con) or \
            any(weather in result['textNight'] for weather in bad_weather_con):
                return True
        return False
  3. 发送邮件:发送邮件需要开启SMTP功能,不同的邮箱有不同的操作流程,请自行百度,在此不多赘述。

    # 发送邮件
    def send_email(subject, body, to_email, from_email, smtp_server, smtp_port, login, password):
        msg = MIMEMultipart()
        msg['From'] = from_email
        msg['To'] = to_email
        msg['Subject'] = subject
        
        # 如果传入的 body 是字典类型,将其转换为字符串
        if isinstance(body, dict):
            body = json.dumps(body, ensure_ascii=False, indent=2)  # 格式化字典为字符串
        
        # 添加正文内容
        msg.attach(MIMEText(body, 'plain'))
    
        try:
            with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
                server.login(login, password)
                server.sendmail(from_email, to_email, msg.as_string())
            print(f"Email sent successfully to {to_email}!")
        except Exception as e:
            print(f"Failed to send email to {to_email}: {e}")
  4. 主函数:

    # 主函数
    # 替换成自己的数据
    def main():
        api_key = ""
        # 城市与邮箱映射,自行添加,如”[email protected]“
        city_mail_map = {
            "长春": [],
            "深圳": []
        }
        # 城市与locationID映射
        city_id_map = {
            "长春": "101060101",
            "深圳": "101280601"
        }
        # 遍历所有城市
        for city, location in city_id_map.items():
            to_emails = city_mail_map.get(city, [])
            
            # 获取数据
            url = f'https://devapi.qweather.com/v7/weather/3d?location={location}&key={api_key}'
            data = requests.get(url).json()
            result = data['daily'][0]
            
            # 判断天气是否恶劣
            if is_bad_weather(result):
                subject = "今日有雨!"
                
                # 邮件配置
                from_email = "Bad weather today <[email protected]>" # 以昵称发送邮件
                smtp_server = "" #换成对应的服务器地址
                smtp_port = 465
                login = "" # 换成自己的邮箱
                password = ""  # 使用应用密码
    
    
                weather_info = get_weather_forecast(api_key, location) 
    
                # 发送邮件给每个目标邮箱
                for to_email in to_emails:
                    send_email(subject, weather_info, to_email, from_email, smtp_server, smtp_port, login, password)
    
    if __name__ == "__main__":
        main()           
    
  5. 定时执行程序:定时执行程序的方式有很多,我选择的是crontab,也就是cron table,它是cron的配置文件,也可以叫作业列表。

    # 编辑工作表
    crontab -e
    
    # crontab的命令构成为 时间+动作,其时间有分、时、日、月、周五种。该命令代表每天5:05执行脚本,*代表分,时,日,月,周
    # 具体可以看:https://www.runoob.com/w3cnote/linux-crontab-tasks.html
    05 5 * * * /usr/bin/python3 /path/to/script.py

项目补充

  1. 邮箱发送可能不太方便接收,因为有的人不习惯查看邮箱通知。在此提供一个微信消息发送的程序,灵感来源于我用来接收博客通知的极简推送API——server酱,官网:https://sct.ftqq.com/

    # 只需要将邮件发送的函数换成下面的函数,再改改主程序的参数即可
    # 发送微信消息
    def send_wechat_message(content, sckey):
        """
        发送消息到微信,使用 Server 酱的 API
        content: 要发送的内容
        sckey: Server酱的 SCKEY
        """
        url = f"https://sc.ftqq.com/{sckey}.send"
        params = {
            "text": "天气预警",  # 消息标题
            "desp": content      # 消息内容
        }
        data = requests.get(url, params=params)
        if data.status_code == 200:
            print("Message sent to WeChat successfully!")
        else:
            print(f"Failed to send message to WeChat: {res.text}")
            

总结

邮件发送天气预报仅是一个示例,实际上,我们可以通过电子邮件、即时消息、云存储分享等多种方式,传递任何类型的文件或信息。无论是报告、图表、文档还是数据,确保我们能够及时、高效地获取和分享有价值的内容。

 

 

 


目录