面倒な手作業をPythonに任せる


# はじめに
[CYBIRD Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cybird) の12日目担当の@cy-naullと申します。サーバサイドエンジニア、CYBIRD Advent Calendar参加、ともに3年目になります。
11日目は、@cy_yusuke_itoさんの「[MongoDBからMySQLへのEmbulkを使った移行](https://qiita.com/cy_yusuke_ito/items/188954e7d456097eb4cb)」でした。ぜひ、こちらもご覧ください！

# 概要
昨年に引き続き、今年も面倒な手作業を自動化していきたいと思います:thinking:
CYBIRD Advent Calendar 2022では「[面倒な手作業をシェルスクリプトに任せる](https://qiita.com/cy-naull/items/ee7bb3a88b1fd13562bd)」にて手作業で行っていた、ログ収集からデータ整形までを自動化することができました。

しかし、完全に自動化したとは言えず、現在、作成したログデータを新規Excelファイルに書き込む作業が発生しており、面倒な手作業に違いありません。
こちらについても手作業で行うより自動化した方が楽！ということで今年は、作成したCSVファイルをExcelファイルに書き込む作業についてPythonを使用し、自動化していこうと思います。

# 目次
1. やりたいこと
1. Pythonで実行できるようにする
1. まとめ

# 1.　やりたいこと
全体的な流れとしては、先月分のログデータに対し、Pythonを使用して以下を実装するかたちになります。

- 用意されているExcel(テンプレート)ファイルをもとに新規Excelファイルを作成
- CSVファイルを読み込む
- 作成したExcelファイルに読み込んだデータを書き込み保存する

# 2. Pythonで実行できるようにする
今回、PythonでExcelファイルを操作するために `openPyXL` というライブラリを使用します。こちらを使用することで、Excelファイルの読み書きを簡単に実装することができます。

https://openpyxl.readthedocs.io/en/stable/

以下のコマンドなどでパッケージを事前にインストールしておきます。

``` console
$ pip install openpyxl
```

 ### ① 用意されているExcelファイル(テンプレート)をもとに新規Excelファイルを作成
 まずは、テンプレートをコピーし新規Excelファイルを作成していきたいと思います。

 テンプレートから新規Excelファイルを作成するには、`openpyxl.load_workbook()` でテンプレートを読み込み、保存する際、引数に新規Excelファイル名を指定することで簡単にコピーすることが可能です。
 今回、引数に指定する新規Excelファイル名を先月の年月にしたかったため `datetime` を使用し、取得しています。また、保存するディレクトリ先もファイル名に含めることができます。
 
 余談ですが、文字列を記述する際に[f文字列](https://docs.python.org/ja/3/reference/lexical_analysis.html#formatted-string-literals)というものがpython3.6から導入され、キャストしたり、format()を使用せずとも簡単に実装することができるようになっており感動しました:eyes:
 

 

 ``` python
 import openpyxl
 import datetime

# パス指定
log_file_path = "/logs"
text_file_path = "/text"

 # 日付取得
dt_today = datetime.date.today()

# 生成するファイル名
excel_file_name = f'log_{dt_today.year}_{dt_today.month - 1}.xlsx'

# テンプレートからコピー作成
excel_template = openpyxl.load_workbook(f'{log_file_path}/log_template.xlsx')
excel_template.save(f'{log_file_path}/{excel_file_name}')
 
 ```

### ② CSVファイルを読み込む
次に、先月のログであるCSVファイルを読み込んでいきます。

先ほどと同様に、`datetime` を使用し先月の年月を取得し、CSVファイルを指定します。`open()` で指定したファイル名、読み取りモード、エンコード方式、最後にエラーを無視するかどうかを入力します。
エラーの取り扱いについては、絵文字などがログに存在した場合文字化けを起こしてしまっていたため、今回は一旦無視することにしました。

 ``` python
 #読み込みたいファイル
text_file_name = f'{dt_today.year}{dt_today.month - 1}.csv'

 with open(f'{text_file_path}/{dt_today.year}{dt_today.month - 1}/{text_file_name}', "r", encoding="utf-8", errors="ignore") as file:
	reader = csv.reader(file)
    ...
 ```

 ### ③ 作成したExcelファイルに読み込んだデータを書き込み保存する
 最後に、①で作成したExcelファイルに、②で読み込んだデータを書き込んでいきます。

テンプレートから作成した新規Excelファイルを`openpyxl.load_workbook()` で読み込みます。読み込んだExcelファイルに書き込むため、シート名を指定します。今回は、テンプレートから作成したためシート名を指定するだけですが、新規でシートを作成する際には、以下のように記述します。

``` python
sheet = excel_wb.create_sheet(title='***')
```

シート名を指定し終わったら、データを書き込みます。読み込んだCSVデータを書き込むためには、Excelシートの列と行を指定してあげるだけです。
例えば、A列の5行目に書き込みたい場合は、`"A5"` とすればOKです。
``` python
excel_sheet["A5"].value = "hoge"
```
このように書き込みたい内容を書き込みたい箇所を指定し、Excelファイルを完成させます。
書き込んだ内容を保存するため、`save()` を行い、自動化が完了となります！

 ``` python
 # コピーしたものを開く
excel_wb = openpyxl.load_workbook(f'{log_file_path}/{excel_file_name}')

# シート名指定
excel_sheet = excel_wb["ログ集計"]

# 書き込む
with open(f'{text_file_path}/{dt_today.year}{dt_today.month - 1}/{text_file_name}', "r", encoding="utf-8", errors="ignore") as file:
	reader = csv.reader(file)
	row_number = 3
	for row in reader:
		excel_sheet[f"B{row_number}"].value = row[0]
		excel_sheet[f"C{row_number}"].value = row[1]
		excel_sheet[f"D{row_number}"].value = row[2]

		row_number += 1

# 保存
excel_wb.save(f'{log_file_path}/{excel_file_name}')
 ```

 # 3. まとめ
昨年に引き続き、今年も面倒な作業をなくすことができハッピーです。Pythonでの実装はライブラリが豊富で思い立ったら実装できる点が心強いと思います。

 次回、[CYBIRD Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cybird) の13日目は @cy-seiyan さんの「タイムアウトが頻発して泣きを見た話」 になります。どのような内容なのでしょう...お楽しみにー！