用python自动生成日历


Posted in Python onApril 24, 2021

效果

用python自动生成日历

在Excel日历模板的基础上,生成带有农历日期、节假日、休班等信息的日历,解决DIY日历最大的技术难题。

图中日期,第一行为公历,第二行为节假日,第三行为农历,第四行是其他特别的日子,比如生日、纪念日等。

特点

  • 使用门槛低

Python + Excel,会运行Python脚本,会使用Excel即可上手。

  • 步骤简单

只需要修改Excel的年份(在一月份表头修改),运行一次脚本

  • 可扩展

可制作任意年份的日历(修改年份即可)

  • 可定制

可以添加其他特殊日期

使用手册

第一步,修改日历年份及样式

打开calendar.xlsx文件,在一月份表头,”输入年份“位置,修改样式

第二步,添加自定义日期

calendar.xlsx文件的生日栏,添加需要标注的日期,并保存

第三部,运行脚本

主要代码

BdDataFetcher.py

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import datetime
import logging
import time

import requests
import re
import json

class BdDataFetcher(object):
    def __init__(self):
        self.url = 'https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php'
        self.request_session = requests.session()
        self.request_session.headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
            "Connection": "keep-alive"
        }

    def request(self, year_month):
        payload = {
            'query': year_month,
            'resource_id': 39043,
            't': int(round(time.time() * 1000)),
            'ie': 'utf8',
            'oe': 'utf8',
            'cb': 'op_aladdin_callback',
            'format': 'json',
            'tn': 'wisetpl',
            'cb': 'jQuery110206747607329442493_1606743811595',
            '_': 1606743811613
        }
        resp = self.request_session.get(url=self.url, params=payload)
        logging.debug('data fetcher resp = {}'.format(resp.text))
        bracket_pattern = re.compile(r'[(](.*?)[)]', re.S)
        valid_data = re.findall(bracket_pattern, resp.text)
        json_data = json.loads(valid_data[0])
        almanac = json_data['data'][0]['almanac']
        result = {}
        for day in almanac:
            key = '{}-{}-{}'.format(day['year'], day['month'],day['day'])
            result[key] = day
        return result
if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                        datefmt='%a, %d %b %Y %H:%M:%S')
    BdDataFetcher().request('2021年1月')

ExcelDateFiller.py

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import logging
import os
import sys
from copy import copy

import openpyxl
import pandas as pandas
import xlrd
import xlutils
import yaml
from pandas._libs.tslibs.timestamps import Timestamp

from BdDataFetcher import BdDataFetcher


class Config(object):
    def __init__(self, config_path):
        try:
            with open(config_path, "r", encoding="utf-8") as yaml_file:
                data = yaml.load(yaml_file)
                self.excel_path = data['excel_path']
                self.sheet_special = data['sheet_special']
                self.skip_row = data['date_skip_row']
                self.skip_col = data['date_skip_col']
                self.max_length = data['max_length']
                self.holiday_color = data['holiday_color']
                self.workday_color = data['workday_color']
                logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                            datefmt='%a, %d %b %Y %H:%M:%S')

        except Exception as e:
            logging.error(repr(e))
            sys.exit()

class SpecialDay(object):
    def __init__(self):
        self.is_lunar = False
        self.desc = ''

class ExcelDateFiller(object):
    def __init__(self):
        self.data_fetcher = BdDataFetcher()
        self.target = os.path.splitext(config.excel_path)[0] + '_out' + os.path.splitext(config.excel_path)[-1]
        # try:
        #     shutil.copy(config.excel_path, self.target)
        # except IOError as e:
        #     print("Unable to copy file. %s" % e)
        # except:
        #     print("Unexpected error:", sys.exc_info())
        # self.target_workbook = openpyxl.load_workbook(self.target, data_only=True)

    def fill_date_with_openpyxl(self):
        for sheet in self.target_workbook.worksheets:
            for column_index in range(1, sheet.max_column):
                for row_index in range(1, sheet.max_row):
                    data = sheet.cell(column=column_index, row=row_index)
                    print(data.value)

    def read_with_xlrd(self):
        workbook = xlrd.open_workbook(self.target)
        for sheet in workbook.sheets():
            for column_index in range(0, sheet.ncols):
                for row_index in range(0, sheet.nrows):
                    data = sheet.cell(rowx=row_index, colx=column_index)
                    logging.debug('ctype = {}, value = {}, xf_index = {}'.format(data.ctype, data.value, data.xf_index))

    def write_with_openpyxl(self):
        target_workbook = openpyxl.load_workbook(self.target)
        sheet = target_workbook.get_sheet_by_name('sheet_name')
        sheet.cell(0, 0).value = 'value'
        target_workbook.save()

    def write_with_xlwt(self):
        workbook = xlrd.open_workbook(self.target)
        workbook = xlutils.copy(workbook)
        sheet = workbook.get_sheet(0)
        sheet.write(0, 0, 'value')
        workbook.save()

    def load_special_sheet(self):
        data = {}
        special_sheet = pandas.read_excel(config.excel_path, sheet_name=config.sheet_special, header=0)
        for row_index in range(special_sheet.shape[0]):
            key = special_sheet.iloc[row_index, 0]
            struct_time = pandas.to_datetime(key.timestamp(), unit='s').timetuple()
            key = '{}-{}'.format(struct_time.tm_mon, struct_time.tm_mday)
            value = SpecialDay()
            value.desc = special_sheet.iloc[row_index, 1]
            value.is_lunar = special_sheet.iloc[row_index, 2] == '是'
            data[key] = value
        return data


    def fill_date(self):
        pandas_workbook = pandas.read_excel(config.excel_path, sheet_name=None, skiprows= config.skip_row, keep_default_na=False)
        out_workbook = openpyxl.load_workbook(config.excel_path)

        special_day = self.load_special_sheet()

        day_data = {}
        for sheet_name in pandas_workbook.keys():
            if not sheet_name.endswith('月'):
                continue
            sheet = pandas_workbook.get(sheet_name)
            out_sheet = out_workbook.get_sheet_by_name(sheet_name)

            nrows = sheet.shape[0]
            ncols = sheet.shape[1]
            for row_index in range(nrows):
                for col_index in range(ncols):
                    data = sheet.iloc[row_index, col_index]
                    logging.debug('origin row = {}, col = {}, data = {}'.format(row_index, col_index, data))
                    if type(data) == Timestamp:
                        struct_time = pandas.to_datetime(data.timestamp(), unit='s').timetuple()
                        date = '{}-{}-{}'.format(struct_time.tm_year, struct_time.tm_mon, struct_time.tm_mday)
                        if not day_data.__contains__(date):
                            request_data = self.data_fetcher.request(year_month='{}年{}月'.format(struct_time.tm_year, struct_time.tm_mon))
                            day_data.update(request_data)

                        temp_row = row_index + 2 + config.skip_row
                        temp_col = col_index + 1
                         # weekend color
                        if day_data[date]['cnDay'] == '六' or day_data[date]['cnDay'] == '日':
                            holiday_font = copy(out_sheet.cell(temp_row, temp_col).font)
                            holiday_font.color = config.holiday_color
                            out_sheet.cell(temp_row, temp_col).font = holiday_font
                        # holiday color
                        if day_data[date].__contains__('status'):
                            if day_data[date]['status'] == '1': # 休假
                                holiday_font = copy(out_sheet.cell(temp_row, temp_col).font)
                                holiday_font.color = config.holiday_color
                                out_sheet.cell(temp_row, temp_col).font = holiday_font
                            if day_data[date]['status'] == '2': #班
                                workday_font = copy(out_sheet.cell(temp_row, temp_col).font)
                                workday_font.color = config.workday_color
                                out_sheet.cell(temp_row, temp_col).font = workday_font
                        lunar_date = day_data[date]['lDate']
                        if lunar_date == '初一':
                            lunar_date = '{}月'.format(day_data[date]['lMonth'])
                        # logging.debug('date = {}, value = {}'.format(str(date), lunar_date))
                        temp_content = ''
                        if day_data[date].__contains__('value'):
                            temp_content += day_data[date]['value']
                            if len(temp_content) > config.max_length:
                                temp_content = temp_content[:config.max_length]
                        temp_content += '\n'
                        temp_content += lunar_date
                        # spacial day
                        month_day = day_data[date]['month'] + '-' + day_data[date]['day']
                        if special_day.__contains__(month_day):
                            temp_special_day = special_day.get(month_day)
                            if not temp_special_day.is_lunar:
                                temp_content += '\n'
                                temp_content += temp_special_day.desc

                        lunar_month_day = day_data[date]['lunarMonth'] + '-' + day_data[date]['lunarDate']
                        if special_day.__contains__(lunar_month_day):
                            temp_special_day = special_day.get(lunar_month_day)
                            if temp_special_day.is_lunar:
                                temp_content += '\n'
                                temp_content += temp_special_day.desc

                        temp_row = row_index + 3 + config.skip_row
                        temp_col = col_index + 1
                        out_sheet.cell(temp_row, temp_col).value = temp_content


        out_workbook.save(filename=self.target)
        out_workbook.close()

if __name__ == '__main__':
    config = Config(config_path='config.yaml')
    date_filler = ExcelDateFiller()
    date_filler.fill_date()

完整项目地址

https://github.com/yongjiliu/diycalendar

calendar_out.xlsx为处理好的日历

以上就是用python自动生成日历的详细内容,更多关于python 生成日历的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
实例讲解Python中的私有属性
Aug 21 Python
python检测远程服务器tcp端口的方法
Mar 14 Python
Python批量创建迅雷任务及创建多个文件
Feb 13 Python
python操作excel的包(openpyxl、xlsxwriter)
Jun 11 Python
Python 3.8正式发布,来尝鲜这些新特性吧
Oct 15 Python
如何修复使用 Python ORM 工具 SQLAlchemy 时的常见陷阱
Nov 19 Python
python批量修改xml属性的实现方式
Mar 05 Python
pycharm实现在子类中添加一个父类没有的属性
Mar 12 Python
python中upper是做什么用的
Jul 20 Python
python 基于UDP协议套接字通信的实现
Jan 22 Python
python如何发送带有附件、正文为HTML的邮件
Feb 27 Python
python实现黄金分割法的示例代码
Apr 28 Python
解决Django transaction进行事务管理踩过的坑
Apr 24 #Python
pdf论文中python画的图Type 3 fonts字体不兼容的解决方案
Apr 24 #Python
Python使用UDP实现720p视频传输的操作
python通配符之glob模块的使用详解
Apr 24 #Python
Django debug为True时,css加载失败的解决方案
Apr 24 #Python
python 模块重载的五种方法
Apr 24 #Python
写一个Python脚本自动爬取Bilibili小视频
You might like
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
深入PHP异步执行的详解
2013/06/03 PHP
解析将多维数组转换为支持curl提交的一维数组格式
2013/07/08 PHP
PHP fopen()和 file_get_contents()应用与差异介绍
2014/03/19 PHP
四个PHP非常实用的功能
2015/09/29 PHP
PHP框架Laravel学习心得体会
2015/10/28 PHP
PHP实现的操作数组类库定义与用法示例
2019/05/24 PHP
解决laravel5.4下的group by报错的问题
2019/10/16 PHP
win10下 php安装seaslog扩展的详细步骤
2020/12/04 PHP
ComboBox 和 DateField 在IE下消失的解决方法
2013/08/30 Javascript
js将当前时间格式转换成时间搓(自写)
2013/09/26 Javascript
js与jQuery 获取父窗、子窗的iframe
2013/12/20 Javascript
获取3个数组不重复的值的具体实现
2013/12/30 Javascript
jquery访问ashx文件示例代码
2014/08/11 Javascript
jquery实现搜索框常见效果的方法
2015/01/22 Javascript
Node.js 学习笔记之简介、安装及配置
2015/03/03 Javascript
Javascript点击其他任意地方隐藏关闭DIV实例
2016/06/21 Javascript
jQuery实现简单弹窗遮罩效果
2017/02/27 Javascript
基于BootStrap实现简洁注册界面
2017/07/20 Javascript
jquery实现限制textarea输入字数的方法
2017/09/06 jQuery
详解vuex结合localstorage动态监听storage的变化
2018/05/03 Javascript
使用vue-infinite-scroll实现无限滚动效果
2018/06/22 Javascript
react 中父组件与子组件双向绑定问题
2019/05/20 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
2019/09/04 Javascript
Layui选项卡制作历史浏览记录的方法
2019/09/28 Javascript
使用Python导出Excel图表以及导出为图片的方法
2015/11/07 Python
python自定义时钟类、定时任务类
2021/02/22 Python
pycharm创建scrapy项目教程及遇到的坑解析
2019/08/15 Python
Python基于class()实现面向对象原理详解
2020/03/26 Python
汽车维修工岗位职责
2014/02/12 职场文书
2014年党务公开方案
2014/05/08 职场文书
校园活动策划方案
2014/06/13 职场文书
创先争优个人总结
2015/03/04 职场文书
惊涛骇浪观后感
2015/06/05 职场文书
springboot+VUE实现登录注册
2021/05/27 Vue.js
python程序的组织结构详解
2021/12/06 Python