見出し画像

Pythonでやってみた5:週報の作成

概要

 毎日同じことしてるのに週報を作成しないといけないので自動化してみました(身バレ防止のためnote専用ファイルで実習)。
 なお本記事を元に別パターンも作成しましたのでご確認ください。

1.サンプルドキュメント

 週報に使用するテンプレートは下記の通りです。

【ファイルの構造】
●署名欄と日ごとの記載欄用のテーブルが2つ
●期間は月曜日~日曜日であり、土日は常に休みとする
●文字列置換をしたいところに重複しない適当な値頭にRPA_をつけましたをふる

2.コード(変数・関数)の説明

 使用するコードの動作を事前説明します。

2-1.月曜日から日曜日の年月日を取得

 本日の日付を取得して今週の月曜日と日曜日の年月日を抽出します。

[In]
import datetime
today = datetime.datetime.now()

def getMonday(date=today):
    date_Mon = datetime.datetime.strptime("{} {} {}".format(date.isocalendar()[0], date.isocalendar()[1], 1), "%Y %W %w")
    date_Sun = datetime.datetime.strptime("{} {} {}".format(date.isocalendar()[0], date.isocalendar()[1], 0), "%Y %W %w")
    Mon_str = date_Mon.strftime("%Y%m%d")
    Sun_str = date_Sun.strftime("%Y%m%d")
    year_Mon, month_Mon, day_Mon = Mon_str[:4], Mon_str[4:6], Mon_str[6:]
    year_Sun, month_Sun, day_Sun = Sun_str[:4], Sun_str[4:6], Sun_str[6:]
    return Mon_str, year_Mon, month_Mon, day_Mon, Sun_str, year_Sun, month_Sun, day_Sun

print(today)
print(getMonday(date=today))
[Out]
2021-12-16 10:05:16.867028
('20211213', '2021', '12', '13', '20211219', '2021', '12', '19')

2-2.年を年度に変更

 年度を記載するために1~3月と4月以降で値を切り替える関数を作成します。なお入力値は2-1.関数の戻り値を使用するためStringにしました。

[In]
def year2fisyear(year: str, month: str) -> str:
    if int(month) <=3:
        return f'{int(year) -1}'
    else:
        return f'{int(year)}'

for i in range(1,13):
    print(f'{i}月->{year2fisyear(str(2022), str(i))}')
[Out]
1月->2021
2月->2021
3月->2021
4月->2022
5月->2022
6月->2022
7月->2022
8月->2022
9月->2022
10月->2022
11月->2022
12月->2022

2-3.文字列置換用の辞書を作成

 python-docxで文字列を置換するために、辞書に "置換用文字列":"置換したい文字"をいれて置換します。そのための辞書を作成します。

【作成する辞書】
パラグラフ(subword1): 表題の年度および今週の年月日
テーブル1(subword2):今週の日付
テーブル2(subword3):業務内容

[In]
#パラグラフ内で置換したい文字列を辞書に格納
subwords1 = {
   'RPA_年月日':today.strftime("%Y年%m月%d日"),
   'RPA_fiscalyear':fiscalyear,
   'RPA_year1':year_Mon,
   'RPA_mm1':month_Mon,
   'RPA_dd1':day_Mon,
   'RPA_year2':year_Sun,
   'RPA_mm2':month_Sun,
   'RPA_dd2':day_Sun,
}

#テーブル内で置換したい文字列を辞書に格納(日付)
def getweekdates(date=today, subwords2={}):
    for i in range(1, 8): #月曜日-日曜日
        mm = 'RPA_mm' + str(i)
        dd = 'RPA_dd' + str(i)
        _ = i
        if _ == 7: i=0
        day = datetime.datetime.strptime("{} {} {}".format(date.isocalendar()[0], date.isocalendar()[1], i), "%Y %W %w")
        subwords2[mm], subwords2[dd] = day.month, day.day
    return subwords2
subwords2 = getweekdates(date=today, subwords2={})

#テーブル内で置換したい文字列を辞書に格納(業務内容)
def writework(subwords3={}):
    for i in range(1, 6): #月曜日-金曜日
        body = 'RPA_body' + str(i)
        if i == 5:
            subwords3[body] = '事務作業(在宅)' #金曜日
        else: 
            subwords3[body] = '事務作業' #月ー木曜日
    return subwords3
subwords3 = writework(subwords3={})

print(subwords1)
print(subwords2)
print(subwords3)
[Out]
#subword1
{'RPA_年月日': '2022年01月15日', 'RPA_fiscalyear': '2021', 'RPA_year1': '2022', 'RPA_mm1': '01', 'RPA_dd1': '10', 'RPA_year2': '2022', 'RPA_mm2': '01', 'RPA_dd2': '16'}
#subwor2
{'RPA_mm1': 1, 'RPA_dd1': 10, 'RPA_mm2': 1, 'RPA_dd2': 11, 'RPA_mm3': 1, 'RPA_dd3': 12, 'RPA_mm4': 1, 'RPA_dd4': 13, 'RPA_mm5': 1, 'RPA_dd5': 14, 'RPA_mm6': 1, 'RPA_dd6': 15, 'RPA_mm7': 1, 'RPA_dd7': 16}
#subword3
{'RPA_body1': '事務作業', 'RPA_body2': '事務作業', 'RPA_body3': '事務作業', 'RPA_body4': '事務作業', 'RPA_body5': '事務作業(在宅)'}

2-4.パラグラフ内の文字列置換

 python-docxでWordを読み込み、辞書に "置換用文字列":"置換したい文字"をいれて置換します。(※下記コードはそのままでは動作しません動作確認用のため実際のコードは次章参照)

[In]
#パラグラフ内で置換したい文字列を辞書に格納
subwords1 = {
   'RPA_年月日':today.strftime("%Y年%m月%d日"),
   'RPA_fiscalyear':fiscalyear,
   'RPA_year1':year_Mon,
   'RPA_mm1':month_Mon,
   'RPA_dd1':day_Mon,
   'RPA_year2':year_Sun,
   'RPA_mm2':month_Sun,
   'RPA_dd2':day_Sun,
}

#パラグラフ内の文字列を置換
doc = docx.Document(wordfile)
for paragraph in doc.paragraphs: #段落ごとにテキストを抽出
    print('Before置換', paragraph.text)
    for key, value in subwords1.items(): #置換対象のキーと値を取得
        if key in paragraph.text: #キーがテキストに含まれているか
            paragraph.text = paragraph.text.replace(key, str(value)) #テキスト内の文字を置換
            print('After置換', paragraph.text)
[Out]
Before置換    RPA_年月日
After置換    2022年01月15日
Before置換 (宛先)Sir
Before置換 
Before置換   RPA_fiscalyear年度  週報
After置換   2021年度  週報
Before置換 (期間:RPA_year1RPA_mm1RPA_dd1 ~ RPA_year2RPA_mm2RPA_dd2  )
After置換 (期間:2022/ RPA_mm1RPA_dd1 ~ RPA_year2RPA_mm2RPA_dd2  )
After置換 (期間:2022/ 01/ RPA_dd1 ~ RPA_year2RPA_mm2RPA_dd2  )
After置換 (期間:2022/ 01/ 10 ~ RPA_year2RPA_mm2RPA_dd2  )
After置換 (期間:2022/ 01/ 10 ~ 2022/ RPA_mm2RPA_dd2  )
After置換 (期間:2022/ 01/ 10 ~ 2022/ 01/ RPA_dd2  )
After置換 (期間:2022/ 01/ 10 ~ 2022/ 01/ 16  )
Before置換 
Before置換 

2-5.テーブル内の文字列置換

 Python-docxはパラグラフとテーブルはまとめて取れないため分けて処理します。また下記は行ごとで処理しますが辞書は列向きに作成しているため1回の処理1つの辞書の置換で1列処理されます。

[In]
table = doc.tables[1] #押印箇所が[0]のため本文テーブルは[1]             

def tablereplace(table, subwords):
    for row in table.rows:
        for cell in row.cells:
            print(cell.text)
            for key, value in subwords.items():
                if key in cell.text:
                    cell.text = cell.text.replace(key, str(value))
                    
tablereplace(table, subwords2)                    
tablereplace(table, subwords3)   

[Out]
完成品参照のこと

2-6.PDF化(docx2pdf)

 python-docxで処理したファイルをwordで保存した後、そのwordファイルをPDF化します。PDF化はdocx2pdfを使用すると簡単にできます。

[In]
from docx2pdf import convert 
convert(filepath)

[Out]
完成品参照のこと

3.今週の週報作成

3-1.記載要領

 週報の記載要領は下記の通りです。

●すべての日で事務作業と記載
●在宅の日は(在宅)と記載する。今回は金曜日のみ
●記載日付は今週の月曜日から日曜日を記載する。

3-2.完成コード

 完成品コードは下記の通りです

[In]
import docx
import glob, os, datetime
from docx2pdf import convert 

#ファイルを開く
wordfile = '週報_KIYO.docx'

#日付を取得して月曜日から日曜日の年月日を取得
today = datetime.datetime.now()

def getMonday(date=today):
    date_Mon = datetime.datetime.strptime("{} {} {}".format(date.isocalendar()[0], date.isocalendar()[1], 1), "%Y %W %w")
    date_Sun = datetime.datetime.strptime("{} {} {}".format(date.isocalendar()[0], date.isocalendar()[1], 0), "%Y %W %w")
    Mon_str = date_Mon.strftime("%Y%m%d") 
    Sun_str = date_Sun.strftime("%Y%m%d")
    year_Mon, month_Mon, day_Mon = Mon_str[:4], Mon_str[4:6], Mon_str[6:]
    year_Sun, month_Sun, day_Sun = Sun_str[:4], Sun_str[4:6], Sun_str[6:]
    return Mon_str, year_Mon, month_Mon, day_Mon, Sun_str, year_Sun, month_Sun, day_Sun

def year2fisyear(year: str, month: str) -> str:
    if int(month) <=3:
        return f'{int(year) -1}'
    else:
        return f'{int(year)}'

Mon_str, year_Mon, month_Mon, day_Mon, Sun_str, year_Sun, month_Sun, day_Sun = getMonday(today)

fiscalyear = year2fisyear(year=year_Mon, month=month_Mon)

#パラグラフ内で置換したい文字列を辞書に格納
subwords1 = {
   'RPA_年月日':today.strftime("%Y年%m月%d日"),
   'RPA_fiscalyear':fiscalyear,
   'RPA_year1':year_Mon,
   'RPA_mm1':month_Mon,
   'RPA_dd1':day_Mon,
   'RPA_year2':year_Sun,
   'RPA_mm2':month_Sun,
   'RPA_dd2':day_Sun,
}

#パラグラフ内の文字列を置換
doc = docx.Document(wordfile)
for paragraph in doc.paragraphs: #段落ごとにテキストを抽出
   for key, value in subwords1.items(): #置換対象のキーと値を取得
       if key in paragraph.text: #キーがテキストに含まれているか
           paragraph.text = paragraph.text.replace(key, str(value)) #テキスト内の文字を置換

#テーブル内で置換したい文字列を辞書に格納(日付)
def getweekdates(date=today, subwords2={}):
    for i in range(1, 8): #月曜日-日曜日
        mm = 'RPA_mm' + str(i)
        dd = 'RPA_dd' + str(i)
        _ = i
        if _ == 7: i=0
        day = datetime.datetime.strptime("{} {} {}".format(date.isocalendar()[0], date.isocalendar()[1], i), "%Y %W %w")
        subwords2[mm], subwords2[dd] = day.month, day.day
    return subwords2
subwords2 = getweekdates(date=today, subwords2={})

#テーブル内で置換したい文字列を辞書に格納(業務内容)
def writework(subwords3={}):
    for i in range(1, 6): #月曜日-金曜日
        body = 'RPA_body' + str(i)
        if i == 5:
            subwords3[body] = '事務作業(在宅)' #金曜日
        else: 
            subwords3[body] = '事務作業' #月ー木曜日
    return subwords3
subwords3 = writework(subwords3={})


table = doc.tables[1] #押印箇所が[0]のため本文テーブルは[1]             

def tablereplace(table, subwords):
    for row in table.rows:
        for cell in row.cells:
            for key, value in subwords.items():
                if key in cell.text:
                    cell.text = cell.text.replace(key, str(value))
                    
tablereplace(table, subwords2)                    
tablereplace(table, subwords3)   

filepath = f'outputs/{os.path.basename(wordfile)[:-9]}({Mon_str}-{Sun_str})_KIYO.docx'
doc.save(filepath)                 

#PDF化
from docx2pdf import convert 
convert(filepath)

4.先週以前の週報をまとめて作成

 下記の通り開始日と何週分かを指定して3章のコードをFor文で回すだけでいけます。

[In]
startdate = datetime.datetime(2021, 11, 1) #開始日を11月1日に指定する
wordfile = '週報_KIYO.docx'

for num in range(0,6):
    date = startdate + datetime.timedelta(days=num*7)
    Mon_str, year_Mon, month_Mon, day_Mon, Sun_str, year_Sun, month_Sun, day_Sun = getMonday(date)
    
    doc = docx.Document(wordfile)
    
    subwords1 = {
        'RPA_年月日':today.strftime("%Y年%m月%d日"),
        'RPA_fiscalyear':fiscalyear,
        'RPA_year1':year_Mon,
        'RPA_mm1':month_Mon,
        'RPA_dd1':day_Mon,
        'RPA_year2':year_Sun,
        'RPA_mm2':month_Sun,
        'RPA_dd2':day_Sun,
    }
    
    for paragraph in doc.paragraphs: #段落ごとにテキストを抽出
        for key, value in subwords1.items(): #置換対象のキーと値を取得
            if key in paragraph.text: #キーがテキストに含まれているか
                paragraph.text = paragraph.text.replace(key, str(value)) #テキスト内の文字を置換
    
    subwords2 = getweekdates(date, subwords2={})
    subwords3 = writework(subwords3={})
    
    table = doc.tables[1] #押印箇所が[0]のため本文テーブルは[1] 
    tablereplace(table, subwords2)                    
    tablereplace(table, subwords3)  
    filepath = f'outputs/{os.path.basename(wordfile)[:-9]}({Mon_str}-{Sun_str})_KIYO.docx'
    doc.save(filepath)       
    convert(filepath)                             

参考記事

 使用した基礎操作・ライブラリは下記の通りです。

 「週報のフォーマットExcelなんだけど?」と言う人は下記記事と本記事ので応用可能です。

 なお私はたまに業務内容を変える必要があるためしていないですが、本当に同じものであれば定期実行・メール送付で完全自動化できます。

あとがき

2022年1月15日:表題を年度fisical yeraにするため関数を追加2-2節

 他にも 下記みたいな感じで作業と確立を辞書かしてランダムで抽出するみたいなこともできるけど自分はつかないので紹介まで。

[In]
import numpy as np
s={"作業A":0.25, "作業B":0.25,"作業C":0.25,"作業D":0.25}
np.random.choice(list(s.keys()), p=list(s.values()))

[Out]
ランダム(それぞれ25%の確率)に作業A~Dが出力

 それにしても見出し画像のフリー素材はあそこまではしたことない駅のホームでPCけどものすごい既視感があるw

この記事が気に入ったらサポートをしてみませんか?