用python自動(dòng)生成日歷
效果
在Excel日歷模板的基礎(chǔ)上,生成帶有農(nóng)歷日期、節(jié)假日、休班等信息的日歷,解決DIY日歷最大的技術(shù)難題。
圖中日期,第一行為公歷,第二行為節(jié)假日,第三行為農(nóng)歷,第四行是其他特別的日子,比如生日、紀(jì)念日等。
特點(diǎn)
- 使用門檻低
Python + Excel,會(huì)運(yùn)行Python腳本,會(huì)使用Excel即可上手。
- 步驟簡(jiǎn)單
只需要修改Excel的年份(在一月份表頭修改),運(yùn)行一次腳本
- 可擴(kuò)展
可制作任意年份的日歷(修改年份即可)
- 可定制
可以添加其他特殊日期
使用手冊(cè)
第一步,修改日歷年份及樣式
打開calendar.xlsx文件,在一月份表頭,”輸入年份“位置,修改樣式
第二步,添加自定義日期
calendar.xlsx文件的生日欄,添加需要標(biāo)注的日期,并保存
第三部,運(yùn)行腳本
主要代碼
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()
完整項(xiàng)目地址
https://github.com/yongjiliu/diycalendar
calendar_out.xlsx為處理好的日歷
以上就是用python自動(dòng)生成日歷的詳細(xì)內(nèi)容,更多關(guān)于python 生成日歷的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python 工具類實(shí)現(xiàn)大文件斷點(diǎn)續(xù)傳功能詳解
用python進(jìn)行大文件下載的時(shí)候,一旦出現(xiàn)網(wǎng)絡(luò)波動(dòng)問題,導(dǎo)致文件下載到一半。如果將下載不完全的文件刪掉,那么又需要從頭開始,如果連續(xù)網(wǎng)絡(luò)波動(dòng),是不是要頭禿了。本文提供斷點(diǎn)續(xù)傳下載工具方法,希望可以幫助到你2021-10-10Python利用PySimpleGUI實(shí)現(xiàn)自制桌面翻譯神器
工作上經(jīng)常需要與外國(guó)友人郵件溝通,奈何工作電腦沒有安裝有道詞典一類的翻譯軟件,結(jié)合自己的需要,自己用PySimpleGUI擼一個(gè)桌面翻譯神器,感興趣的可以了解一下2022-09-09將django項(xiàng)目部署到centos的踩坑實(shí)戰(zhàn)
Django部署到Cenos需要安裝大量的依賴包, 有很多坑需要踩,這篇文章主要給大家介紹了關(guān)于將django項(xiàng)目部署到centos踩坑的相關(guān)資料,需要的朋友可以參考下2021-07-07詳解Python如何使用Self類型實(shí)現(xiàn)返回類的實(shí)例對(duì)象
在 Python 中,類方法通常會(huì)返回類的實(shí)例對(duì)象,本文將詳細(xì)介紹如何在 Python 中使用 Self 類型來(lái)返回類的實(shí)例對(duì)象,并提供豐富的示例代碼幫助更好地理解,快跟隨小編一起學(xué)習(xí)起來(lái)吧2024-02-02Python異步處理返回進(jìn)度——使用Flask實(shí)現(xiàn)進(jìn)度條
這篇文章主要介紹了Python異步處理返回進(jìn)度——使用Flask實(shí)現(xiàn)進(jìn)度條,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05python批量導(dǎo)入數(shù)據(jù)進(jìn)Elasticsearch的實(shí)例
今天小編就為大家分享一篇python批量導(dǎo)入數(shù)據(jù)進(jìn)Elasticsearch的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05簡(jiǎn)單了解Python多態(tài)與屬性運(yùn)行原理
這篇文章主要介紹了簡(jiǎn)單了解Python多態(tài)與屬性運(yùn)行原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06pyqt QGraphicsView 以鼠標(biāo)為中心進(jìn)行縮放功能實(shí)現(xiàn)
在PyQt開發(fā)中,實(shí)現(xiàn)QGraphicsView的鼠標(biāo)中心縮放功能需要注意初始化以及關(guān)鍵函數(shù)的重定義,遇到不達(dá)預(yù)期的效果時(shí),可能需要重寫所有鼠標(biāo)事件,本文記錄了解決QGraphicsView鼠標(biāo)縮放問題的過(guò)程,供開發(fā)者參考2024-10-10PyCharm連接遠(yuǎn)程服務(wù)器配置的全過(guò)程
這篇文章主要介紹了PyCharm連接遠(yuǎn)程服務(wù)器配置的全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06