今回も前回に続いてエクセル+Pythonです。これまでは読み出すばかりでしたが、今回はエクセルファイルを生成します。そして、生成したエクセルファイルに必要なデータや関数式を書き込みます。最終調整はエクセル上で行うにしても、その前段階まで準備できていれば作業効率も上がるかもしれません。
これまでと同様に処理するエクセルデータと実行するPythonスクリプトは同じフォルダ(デスクトップ上にあるsampleフォルダ)にあるものとします。また、保存先のエクセルファイルもsampleフォルダになります。もし、保存先を変えたい場合はスクリプト(プログラム)中のファイルのファイル名(ファイルパス)を変更してください。

新規にエクセルファイルを作成しセルに内容を書き込む

 まずは新規にエクセルファイルを作成してみましょう。これまでと同様にOpenPyXLライブラリを読み込ませます。あとは、openpyxl.Workbook()とすれば新規にエクセルファイルが作成されます。
 作成したエクセルファイルを保存するにはsave()を使います。()の中に保存するファイル名を指定します。任意のフォルダ(ディレクトリ)に保存する場合はファイル名の部分をファイルパスに変更してください。
 新規にエクセルファイルを保存するプログラムは以下のようになります。コマンドラインから実行すると何も入っていないエクセルファイルが作成されます。

import openpyxl
wb = openpyxl.Workbook()
wb.save('test1.xlsx')

 新規にエクセルファイルを作成しただけでは意味がないので、今度は任意の文字列を書き込んでみましょう。任意のセルに文字列を入れるにはワークシートのセル位置を指定します。指定したセルのvalueに''で囲んで文字列を入れます。
 A1のセルにABCの文字を入れるプログラムは以下のようになります。

import openpyxl
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = 'ABC'
wb.save('test2.xlsx')

エクセルでは文字列だけでなく数値や関数式をセルに入れることができます。数値の場合は、そのまま数値を書けばOKです。関数式の場合は文字列として関数式をそのまま指定します。
以下のプログラムはA1セルとB1セルに数値を入れて、それらのセルの合計をD1セルに表示します。

import openpyxl
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = 123
ws['B1'].value = 456
ws['D1'].value = '=SUM(A1,B1)'
wb.save('test3.xlsx')

セルに日付を書き込む

 セルに書き込むのは文字列や数値だけではありません。例えばデータを取得した日付や時間などを入れたいこともあります。ということで次に日付をセルに入れてみます。
 日付を扱う場合はdatetimeライブラリを使います。このライブラリを読み込ませれば様々な日付データを取得することができます。日付をセルに入れる場合はdate()のパラメーターに年月日を順番に指定します。
 以下のプログラムはA1のセルに2024年12月25日の日付を入れます。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = datetime.date(2024,12,25)
wb.save('test4.xlsx')

 任意の日付ではなくエクセルのファイルを生成した当日、つまり今日の日付をセルに入れることもできます。今日の日付はtoday()で取得できます。これを、そのままセルに入れます。
 以下の例ではプログラムを実行した時の日付をA1セルに入れます。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = datetime.date.today()
wb.save('test5.xlsx')

 日付だけでなく時間もセルに入れたい場合は以下のようになります。date部分がdatetimeに変わっただけです。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = datetime.datetime.today()
wb.save('test6.xlsx')

 年月日を別々のセルに入れることもできます。この場合はyearが西暦年、monthが月、dayが日にちのプロパティになります。
 以下のプログラムはA1セルにプログラムを実行した時の西暦年、B1セルに月、C1に日にちを入れます。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = datetime.date.today().year
ws['B1'].value = datetime.date.today().month
ws['C1'].value = datetime.date.today().day
wb.save('test7.xlsx')

 フォーマット文字列を使ってセルに日時を入れることもできます。  以下の例ではプログラムを実行した時の時分秒をA1,B1,C1のセルに入れます。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
d = datetime.datetime.now()
ws['A1'].value = d.strftime('%H')
ws['B1'].value = d.strftime('%M')
ws['C1'].value = d.strftime('%S')
wb.save('test8.xlsx')

 日付を別々のセルに入れるのではなく1つのセルにまとめて入れることもできます。フォーマット文字列を使わずに単純連結する場合は以下のようになります。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
d = datetime.date.today()
ws['A1'].value = '宇宙暦'+str(d.year)+'年'+str(d.month)+'月'+str(d.day)+'日'
wb.save('test9.xlsx')

セルの横幅を変更する

 長い文字列や日付ではセルをはみ出してしまったり、###となって表示しきれないことを示す記号が表示されてしまうことがあります。できれば、横幅もプログラムで調整しておけば作業が楽になります。
 横幅はcolumn_dimensions[〜]の〜の部分に列名(AとかBとか)の文字列を指定し、widthプロパティに値を入れることで変更ができます。
 以下の例ではA列の横幅を13にしています。横幅を調整したので自動的に日付が表示される列幅になっています。

import openpyxl
import datetime
wb = openpyxl.Workbook()
ws = wb.active
d = datetime.date.today()
ws['A1'].value = str(d.year)+'年'+str(d.month)+'月'+str(d.day)+'日'
ws.column_dimensions['A'].width = 13
wb.save('test10.xlsx')

シェルで値を指定してセルに書き込む

 ここまでできれば後はシェルからエクセルファイルを生成できるでしょう。まずは、シェルでA1に文字列を書き込むプログラムです。シェルで指定した値がエクセルファイルに書き込まれているのがわかります。

import openpyxl
import sys
wb = openpyxl.Workbook()
ws = wb.active
ws['A1'].value = sys.argv[1]
wb.save('test11.xlsx')

 常にA1セルに値を書き込むだけでは何の役にも立ちません。シェル側でセル位置を指定し、そこに書き込むように変更します。以下のプログラムをシェルから実行すると任意のセルに好きな文字列や数値を書き込むことができます。

import openpyxl
import sys
wb = openpyxl.Workbook()
ws = wb.active
ws[sys.argv[1]].value = sys.argv[2]
wb.save('test12.xlsx')

 セルの名前ではなくセルの位置を指定して書き込む場合は以下のようになります。

import openpyxl
import sys
wb = openpyxl.Workbook()
ws = wb.active
ws.cell(int(sys.argv[1]),int(sys.argv[2])).value = sys.argv[3]
wb.save('test13.xlsx')

シェルで複数のセルに値を書き込む

 最後にシェルで繰り返しを使って複数のセルに値を入れてみます。値はここでは乱数値とします。
 注意点としては、これまでは1つのPythonプログラムで新規作成から保存まで行っていましたが、連続して書き込む場合は新規ファイルの作成と、セルにデータを書き込むプログラムを別々にしておく必要があります。
 まず、新規にファイルを作成するPythonプログラムは以下のようになります。任意のエクセルファイルを作成できるようにシェルからのパラメーターを指定できるようにしています。

・ew14a.py

import openpyxl
import sys
wb = openpyxl.Workbook()
wb.save(sys.argv[1])

 次に既存のエクセルファイルに任意の位置に値を書き込むPythonプログラムは以下のようになります。

・ew14b.py

import openpyxl
import sys
wb = openpyxl.load_workbook(sys.argv[1])
ws = wb.active
ws.cell(int(sys.argv[2]),int(sys.argv[3])).value = sys.argv[4]
wb.save(sys.argv[1])

 ここまでできてしまえば、後はシェルスクリプトのforで繰り返すだけです。

#!/bin/bash
python ew14a.py $1
for ((i=1; i <= 10; i++)); do
    python ew14b.py $1 $i 1 $RANDOM
done

 シェルスクリプトで作成するエクセルファイル名を指定すればランダム値が入ったエクセルファイルが生成されます。

 実行速度は例によって低速ですが、シェルスクリプトで任意の位置に任意のデータを入れることができるので最低限のことはできることになります。後は、罫線やら列の横幅などを設定すればよいでしょう。

著者 仲村次郎
いろいろな事に手を出してみたものの結局身につかず、とりあえず目的の事ができればいいんじゃないかみたいな感じで生きております。