使用Python3脚本检查节假日并通过企业微信发送每日信息

news2024/11/15 12:13:39

文章目录

  • 简介
  • 环境配置
    • 企业微信机器人
      • 创建群聊
      • 设置机器人信息
  • 脚本详解
    • 导入必要的库
    • 获取节假日信息
    • 判断是否为工作日或节假日
    • 获取天气预报
    • 获取每日一句
    • 发送消息到微信
    • 主函数
  • 加入定时任务
  • 总结
  • 完整代码


简介

在日常工作和生活中,自动化任务可以帮助我们节省大量时间和精力。本文将介绍如何编写一个Python脚本,该脚本可以检查指定日期是否为节假日,并在工作日通过企业微信发送每日信息,包括天气预报和每日一句励志话语。此脚本综合了多个功能模块,包括节假日判断、天气预报获取、每日句子读取和消息发送。

环境配置

首先,确保你的环境中安装了以下Python库:

pip install requests parsel

企业微信机器人

每个机器人发送的消息不能超过20条/分钟。

创建群聊

同样也是先创建群,需要在创建群后再手机端创建机器人
在这里插入图片描述

设置机器人信息

在这里插入图片描述

脚本详解

导入必要的库

import json
import re
import requests
from datetime import datetime
from parsel import Selector

这些库分别用于处理JSON数据、正则表达式、HTTP请求、日期时间和HTML解析。

获取节假日信息

节假日信息来源于万年历。我们通过以下函数获取指定月份的节假日数据:

def get_calendar(year_and_month):
    url = "https://wannianrili.bmcx.com/ajax/"
    params = {"q": year_and_month, "v": "22121303"}
    headers = {"User-Agent": "Mozilla/5.0"}
    res = requests.get(url, params=params, headers=headers)
    sel = Selector(text=res.text)
    rows = sel.css(".wnrl_riqi")

    data = {}
    for row in rows:
        class_name = row.css("a::attr(class)").extract_first("").strip()
        day = row.css("a::attr(onclick)").extract_first("").strip()
        comment = row.css(".wnrl_td_bzl::text").extract_first("").strip()
        ret = re.search("\d{4}-\d{2}-\d{2}", day)
        day = ret.group(0)
        data[day] = {"class_name": class_name, "comment": comment}

    return data

判断是否为工作日或节假日

使用上面获取的数据,我们可以判断某一天是否为工作日或节假日:

def get_day_item(day):
    calendar = get_calendar("-".join(day.split("-")[:2]))
    return calendar.get(day)

def is_workday(day):
    workday_class_list = ["", "wnrl_riqi_ban"]
    day_item = get_day_item(day)
    if day_item:
        return day_item.get("class_name") in workday_class_list
    return False

def is_holiday(day):
    holiday_class_list = ["wnrl_riqi_xiu", "wnrl_riqi_mo"]
    day_item = get_day_item(day)
    if day_item:
        return day_item.get("class_name") in holiday_class_list
    return False

获取天气预报

通过API获取当天的天气预报北京

def get_weather():
    url = "http://t.weather.itboy.net/api/weather/city/101010100"
    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()
        forecast = data.get("data", {}).get("forecast", [])
        today = datetime.now().strftime("%Y-%m-%d")

        for item in forecast:
            if item.get("ymd") == today:
                high = item.get("high", "未知")
                low = item.get("low", "未知")
                weather_type = item.get("type", "未知")
                notice = item.get("notice", "未知")

                weather_report = (
                    f"今日气温 {low} - {high},天气情况:{weather_type}\n"
                    f"温馨提示:{notice}"
                )
                return weather_report
        return "无法获取今天的天气信息"
    else:
        return f"请求失败,状态码:{response.status_code}"

获取每日一句

从本地文件中读取每日一句:

  • 索引文件:current_index.txt 用于跟踪当前读取的行数。如果这个文件不存在,则初始化为0。
  • 文本文件:XMYX-0.txt 包含要读取的句子。每次调用 get_daily_sentence 时,从这个文件中读取下一行。
  • 读取和更新:函数从文件中读取当前行的句子,并在每次调用后更新 current_index.txt 文件中的索引。如果 XMYX-0.txt 文件中的行数少于调用次数,函数会返回“没有更多的句子”。

确保 current_index.txtXMYX-0.txt 文件与脚本在同一目录下。如果 XMYX-0.txt 文件的行数少于调用次数,函数会在读取完所有句子后返回“没有更多的句子”。

def get_daily_sentence():
    index_file = "/data/script/qqq/current_index.txt"
    text_file = "/data/script/qqq/XMYX-0.txt"

    try:
        with open(index_file, "r") as f:
            index = int(f.read().strip())
    except (FileNotFoundError, ValueError):
        index = 0

    try:
        with open(text_file, "r", encoding="utf-8") as f:
            lines = f.readlines()
        if index < len(lines):
            sentence = lines[index].strip()
        else:
            sentence = "没有更多的句子"
    except FileNotFoundError:
        sentence = "句子文件不存在"

    index += 1
    with open(index_file, "w") as f:
        f.write(str(index))

    return sentence

发送消息到微信

通过企业微信Webhook发送消息:

def send_to_wechat(content):
    url = "https://qyapi.weixin.qq.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    headers = {"Content-Type": "application/json"}
    data = {"msgtype": "text", "text": {"content": content}}
    response = requests.post(url, headers=headers, data=json.dumps(data))
    return response.status_code

主函数

结合以上功能模块,实现每天在工作日发送消息:

if __name__ == "__main__":
    today = datetime.now().strftime("%Y-%m-%d")

    if is_workday(today) and not is_holiday(today):
        weather_report = get_weather()
        daily_sentence = get_daily_sentence()

        message_content = (
            "各位同学早上好!\n"
            + "    "
            + weather_report.replace("\n", "\n    ")
            + "\n"
            + "    "
            + daily_sentence.replace("\n", "\n    ")
            + "新的一天,早安!"
        )

        status_code = send_to_wechat(message_content)
        if status_code == 200:
            print("消息发送成功")
        else:
            print(f"消息发送失败,状态码:{status_code}")

加入定时任务

#企业微信通知
0 9 * * * /usr/bin/python3  /data/script/qqq/start.py

在每个小时的第0分钟(即每个小时的开始),如果当前小时是9,
那么就执行 /usr/bin/python3 /data/script/qqq/start.py 这个命令。
但是,这里有一个小的误解点需要澄清。Cron作业中的时间字段并不直接表示“如果当前小时是9”,而是分别独立地指定了分钟、小时、日、月和星期几。在这个例子中,各个字段的含义如下:

0(分钟):表示在每个小时的第0分钟执行。
9(小时):表示在每天的09:00时执行。
接下来的两个*(日和月):分别表示每个月的每一天和每年的每个月。
最后一个*(星期几):表示不考虑星期几,每天都可能执行(但由于前面的小时字段已经明确指定为09:00,所以实际上只会在09:00执行)。
因此,这条Cron作业实际上会在每天的09:00执行指定的Python脚本,而不是仅仅在“如果当前小时是9”的条件下执行。由于分钟字段被设置为0,所以它会精确地在09:00这个时刻执行。

总结来说,这条Cron作业会在每天的09:00使用Python 3解释器执行位于/data/script/qqq/目录下的start.py脚本。

总结

通过这个脚本,我们可以每天自动获取天气信息和每日一句,并在工作日通过企业微信发送给指定的群聊。这不仅节省了人工操作时间,还能提高日常信息传递的效率。你可以根据自己的需求,进一步扩展这个脚本,例如添加更多的数据来源或定制化消息内容。希望这个教程对你有所帮助,欢迎分享和交流你的实现和改进。

完整代码

# -*- coding: utf-8 -*-
"""
@Date    : 2024-07-30
"""

import json
import re  # 添加此行
import requests
from datetime import datetime
from parsel import Selector

def get_calendar(year_and_month):
    """
    获取指定月份的日历信息,包括节假日和特殊备注
    数据来源:https://wannianrili.bmcx.com/

    @param year_and_month: 年月,格式为 'YYYY-MM'
    @return: 字典,键为日期,值为包含 class_name 和 comment 的字典
    """
    url = "https://wannianrili.bmcx.com/ajax/"
    params = {"q": year_and_month, "v": "22121303"}
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0"
    }
    res = requests.get(url, params=params, headers=headers)
    sel = Selector(text=res.text)
    rows = sel.css(".wnrl_riqi")

    data = {}
    for row in rows:
        class_name = row.css("a::attr(class)").extract_first("").strip()
        day = row.css("a::attr(onclick)").extract_first("").strip()
        comment = row.css(".wnrl_td_bzl::text").extract_first("").strip()
        ret = re.search(r"\d{4}-\d{2}-\d{2}", day)
        day = ret.group(0)
        data[day] = {"class_name": class_name, "comment": comment}

    return data

def get_day_item(day):
    """
    获取指定日期的节假日信息

    @param day: 日期,格式为 'YYYY-MM-DD'
    @return: 包含 class_name 和 comment 的字典
    """
    calendar = get_calendar("-".join(day.split("-")[:2]))
    return calendar.get(day)

def is_workday(day):
    """
    判断指定日期是否为工作日

    @param day: 日期,格式为 'YYYY-MM-DD'
    @return: 如果是工作日返回 True,否则返回 False
    """
    workday_class_list = ["", "wnrl_riqi_ban"]
    day_item = get_day_item(day)
    if day_item:
        return day_item.get("class_name") in workday_class_list
    return False

def is_holiday(day):
    """
    判断指定日期是否为节假日

    @param day: 日期,格式为 'YYYY-MM-DD'
    @return: 如果是节假日返回 True,否则返回 False
    """
    holiday_class_list = ["wnrl_riqi_xiu", "wnrl_riqi_mo"]
    day_item = get_day_item(day)
    if day_item:
        return day_item.get("class_name") in holiday_class_list
    return False

def get_weather():
    """
    获取今天的天气信息

    @return: 包含今天气温和天气情况的字符串
    """
    url = "http://t.weather.itboy.net/api/weather/city/101010100"
    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()
        forecast = data.get("data", {}).get("forecast", [])
        today = datetime.now().strftime("%Y-%m-%d")

        for item in forecast:
            if item.get("ymd") == today:
                high = item.get("high", "未知")
                low = item.get("low", "未知")
                weather_type = item.get("type", "未知")
                notice = item.get("notice", "未知")

                weather_report = (
                    f"今日气温 {low} - {high},天气情况:{weather_type}\n"
                    f"温馨提示:{notice}"
                )
                return weather_report
        return "无法获取今天的天气信息"
    else:
        return f"请求失败,状态码:{response.status_code}"

def get_daily_sentence():
    """
    从文件中按顺序读取每日一句

    @return: 每日一句的字符串
    """
    index_file = "/data/script/qqq/current_index.txt"
    text_file = "/data/script/qqq/XMYX-0.txt"

    try:
        with open(index_file, "r") as f:
            index = int(f.read().strip())
    except (FileNotFoundError, ValueError):
        index = 0

    try:
        with open(text_file, "r", encoding="utf-8") as f:
            lines = f.readlines()
        if index < len(lines):
            sentence = lines[index].strip()
        else:
            sentence = "没有更多的句子"
    except FileNotFoundError:
        sentence = "句子文件不存在"

    index += 1
    with open(index_file, "w") as f:
        f.write(str(index))

    return sentence

def send_to_wechat(content):
    """
    发送消息到企业微信

    @param content: 消息内容
    @return: HTTP 响应状态码
    """
    url = "https://qyapi.weixin.qq.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    headers = {"Content-Type": "application/json"}
    data = {"msgtype": "text", "text": {"content": content}}
    response = requests.post(url, headers=headers, data=json.dumps(data))
    return response.status_code

if __name__ == "__main__":
    today = datetime.now().strftime("%Y-%m-%d")
    # 检查今天是否为工作日且不是节假日
    if is_workday(today) and not is_holiday(today):
        weather_report = get_weather()
        daily_sentence = get_daily_sentence()

        # 生成消息内容
        message_content = (
            "各位同学早上好!\n"
            + "    " + weather_report.replace("\n", "\n    ") + "\n"
            + "    " + daily_sentence.replace("\n", "\n    ") + "\n"
            + "新的一天,早安!"
        )
        # print(message_content)
        
        # 发送消息到企业微信
        status_code = send_to_wechat(message_content)
#        if status_code == 200:
#            print("消息发送成功")
#        else:
#            print(f"消息发送失败,状态码:{status_code}")
#    else:
#        print("今天是节假日或非工作日,不发送消息。")

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1977126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

吃惊!这个Windows双系统方法逆天了|UEFI篇

前言 最近小白在折腾别的系统教程&#xff0c;偶然间发现居然有一个很nice的Windows双系统教程。于是于是&#xff0c;果断尝试了一下&#xff0c;发现真的很可行&#xff01; 这个双系统的办法并不需要使用到WinPE系统&#xff0c;因此并不需要使用到U盘&#xff0c;只需要在…

科普文:微服务之SpringBoot性能优化器动态线程池【Dynamic-Tp】特性和源码解读

一、简述 gitee地址&#xff1a;https://gitee.com/yanhom/dynamic-tp github地址&#xff1a;https://github.com/lyh200/dynamic-tp dynamic-tp是一个轻量级的动态线程池插件&#xff0c;它是一个基于配置中心的动态线程池&#xff0c;线程池的参数可以通过配置中心配置进…

数的三次方根

题目 给定一个浮点数 n&#xff0c;求它的三次方根。 输入格式 共一行&#xff0c;包含一个浮点数 n。 输出格式 共一行&#xff0c;包含一个浮点数&#xff0c;表示问题的解。 注意&#xff0c;结果保留 6 位小数。 数据范围 输入样例&#xff1a; 1000.00 输出样例&a…

征服数据结构中的时间和空间复杂度

目录 时间复杂度推导大O方法求解时间复杂度的方法普通顺序结构单循环双循环递归Master定理&#xff08;主定理&#xff09;递归树方法 空间复杂度 一个算法的好坏根据什么来判断呢&#xff1f;有两种一种是时间效率&#xff0c;一种是空间效率。时间效率也可称为时间复杂度&…

内网穿透--LCX+portmap转发实验

实验背景 通过公司带有防火墙功能的路由器接入互联网&#xff0c;然后由于私网IP的缘故&#xff0c;公网 无法直接访问内部web服务器主机&#xff0c;通过内网其它主机做代理&#xff0c;穿透访问内网web 服务器主机 实验设备 1. 路由器、交换机各一台 2. 外网 kali 一台&…

网络层和数据链路层的理解

文章目录 网络层IP协议网段划分IP地址数量问题NAT技术DNSICMP协议 数据链路层以太网MTU的影响ARP协议 网络层 作用&#xff1a; 在网络环境中确定消息传输的路径。 主要协议&#xff1a; IP协议。 IP协议 IP协议的基本概念&#xff1a;凡是入网的机器都会有一个IP地址&#…

手机上音乐如何转换成MP3格式?分享5款音频格式转换APP

手机上音乐如何转换成MP3格式&#xff1f;相信很多外出办公或者不经常使用电脑的工作人士&#xff0c;学生党&#xff0c;媒体从业者都有这样的疑惑和需求。不同设备和应用可能支持不同的音频格式&#xff0c;导致某些情况下需要将音乐文件转换为MP3格式以确保兼容性。下面&…

24暑假算法刷题 | Day27 | 贪心算法 I | LeetCode 455. 分发饼干,376. 摆动序列,53. 最大子数组和

目录 455. 分发饼干题目描述题解 376. 摆动序列题目描述题解 53. 最大子数组和题目描述题解 455. 分发饼干 点此跳转题目链接 题目描述 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#x…

【Mind+】掌控板入门教程03 节日的祝福

在节日的时候&#xff0c;我们通常会送朋友或者家人一张贺卡表达美好的祝福。随着科技的发展&#xff0c;我们已经可以通过手机聊天工具发送一封电子贺卡。电子贺卡相当于把祝福做成了一个小动画&#xff0c;它环保方便&#xff0c;生动有趣。今天就让我们用掌控板来制作一份电…

Java | Leetcode Java题解之第318题最大单词长度乘积

题目&#xff1a; 题解&#xff1a; class Solution {public int maxProduct(String[] words) {Map<Integer, Integer> map new HashMap<Integer, Integer>();int length words.length;for (int i 0; i < length; i) {int mask 0;String word words[i];in…

Java | Leetcode Java题解之第319题灯泡开关

题目&#xff1a; 题解&#xff1a; class Solution {public int bulbSwitch(int n) {return (int) Math.sqrt(n 0.5);} }

C++客户端Qt开发——多线程编程(二)

多线程编程&#xff08;二&#xff09; ③线程池 Qt中线程池的使用 | 爱编程的大丙 1>线程池 我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a;如果并发的线程数量很多&#xff0c;并且每个线程都是执行…

Java:Thread类以及线程状态

文章目录 Thread类等待一个线程 - join()获取当前线程的引用sleep 线程状态 Thread类 等待一个线程 - join() 操作系统,针对多个线程的执行,是一个"随机调度,抢占式执行“的过程. 线程等待就是在确定两个线程的"结束顺序”. 我们无法确定两个线程调度执行的顺序,但…

找工作,如何写一份好的简历? 附简洁大方的简历模板

一份精心制作的简历对给潜在雇主留下积极的第一印象至关重要。这是你展示技能、经验和成就的第一机会&#xff0c;因此制作一份出色的简历至关重要。下面是一个指南&#xff0c;帮助你创建一份出色的简历&#xff0c;参考一个专业的模板。 1. 联系信息 在简历顶部提供你的联系…

设计模式 - Singleton pattern 单例模式

文章目录 定义单例模式的实现构成构成UML图 单例模式的六种实现懒汉式-线程不安全懒汉式-线程安全饿汉式-线程安全双重校验锁-线程安全静态内部类实现枚举实现 总结其他设计模式文章&#xff1a;最后 定义 单例模式是一种创建型设计模式&#xff0c;它用来保证一个类只有一个实…

MATLAB优化模型(4)

一、前言 在MATLAB中&#xff0c;你可以使用内置的遗传算法(Genetic Algorithm)、模拟退火(Simulated Annealing)等优化工具箱函数&#xff0c;或者编写自定义代码来实现(Ant Colony Optimization, ACO) 蚁群算法和粒子群算法(Particle Swarm Optimization, PSO)。以下是一些基…

日撸Java三百行(day12:顺序表二)

目录 一、关于昨天的补充 1.final关键字 2.toString()方法 二、今日代码实现 1.顺序表的查找操作 2.顺序表的插入操作 3.顺序表的删除操作 4.数据测试 总结 一、关于昨天的补充 1.final关键字 public static final int MAX_LENGTH 10; 在昨天的这行代码中&#xf…

OpenCV||超详细的灰度变换和直方图修正

一、点运算 概念&#xff1a;点运算&#xff08;也称为像素级运算或单像素操作&#xff09;是指对图像中每一个像素点进行独立、相同的操作&#xff0c;而这些操作不会考虑像素点之间的空间关系。点处理优势也称对比度拉伸、对比度增强或灰度变换等。 目的&#xff1a;点运算…

操作系统|day3.锁、I/O多路复用、中断

协程 概念 协程是微线程&#xff0c;在子程序内部执行&#xff0c;可在子程序内部中断&#xff0c;转而执行别的子程序&#xff0c;在适当的时候再返回来接着执行。 优势 协程调用跟切换比线程效率高&#xff1a;协程执行效率极高。协程不需要多线程的锁机制&#xff0c;可…

项目经验分享:用4G路由器CPE接海康NVR采用国标GB28181协议TCP被动取流一段时间后设备就掉线了

最近我们在做一个生态化养殖的项目时&#xff0c;发现一个奇怪的现象&#xff1a; 项目现场由于没有有线网络&#xff0c;所以&#xff0c;我们在现场IPC接入到海康NVR之后&#xff0c;再通过一款4G的CPE接入到天翼云的国标GB28181视频平台&#xff1b;我们采用UDP协议播放NVR…