LoginSignup
27
29

More than 5 years have passed since last update.

openpyxlを使ってみた

Last updated at Posted at 2017-03-28

Excelをテンプレートとして読み込んで、編集した後に出力したかったのでOpenPyXLを使ってみたのでメモ書き程度に使ってみた結果を書きとどめてみた。
基本的な使い方は下記を参照。
https://openpyxl.readthedocs.io/en/stable/

結合されたセルの罫線が消える

load → saveで結合されたセルの罫線の一部が消える。

from openpyxl import load_workbook
wb = load_workbook('./test.xlsx')
wb.save('./test2.xlsx')

before:
image

after:
image

ドキュメント読むとそういうものなので諦めるしか無いみたい。
http://openpyxl.readthedocs.io/en/default/styles.html#styling-merged-cells

なのでloadするexcelでは結合せずに罫線を引いておいて、load後にmerge_cells()で結合するしかない。。めんどくさい。

スタイルのコピー

copyを使ってできるらしい。
http://openpyxl.readthedocs.io/en/default/styles.html#copying-styles

けど全てのスタイルをコピーしたい場合にどうしたらいいのかよくわからなかったので調べるとborderとかfontとか指定してコピーしたらって提案がされている。
http://stackoverflow.com/questions/23332259/copy-cell-style-openpyxl#answer-34838233

for row in default_sheet.rows:
    for cell in row:
        new_cell = new_sheet.cell(
                   row=cell.row_idx, col=cell.col_idx, value= cell.value)
        if cell.has_style:
            new_cell.font = cell.font
            new_cell.border = cell.border
            new_cell.fill = cell.fill
            new_cell.number_format = cell.number_format
            new_cell.protection = cell.protection
            new_cell.alignment = cell.alignment

正直めんどいし、これがスタイルの全てかわからんなぁ、って思ってopenpyxlのソースコード見てたらopenpyxl.worksheet.copier._copy_cellstarget_cell._style = copy(source_cell._style)ってしているのを見つけた。
https://bitbucket.org/openpyxl/openpyxl/src/644ea21bb4056f93184d3e743f4abf05c51f84af/openpyxl/worksheet/copier.py?at=default&fileviewer=file-view-default#copier.py-54

ということでスタイルを全コピーする場合は下記で対応する。

to_cell._style = copy(cell._style)

というかセルをコピーする場合はopenpyxl.worksheet.copier._copy_cellsを参考にするといいと思う。
https://bitbucket.org/openpyxl/openpyxl/src/644ea21bb4056f93184d3e743f4abf05c51f84af/openpyxl/worksheet/copier.py?at=default&fileviewer=file-view-default#copier.py-46:60

row_dimensionsは1番目から設定されている

テンプレートから行単位でコピーする場合に行の高さを取得してコピー先の行に設定したくなったりするのだけれども、そんなときにworksheetのrow_dimensionsにアクセスする必要がある。
ただ、1行目のrow_dimensionsはrow_dimensions[0]ではなくrow_dimensions[1]に入っているので間違えないようにする。

範囲指定してコピーする

とあるデータの件数分テンプレートのシートから行をコピーして出力したかったので範囲指定してコピーする関数を実装してみた。

def copy_cell_range(from_sheet, from_range_string, to_sheet, to_cell_string='A1'):
    to_cell = to_sheet[to_cell_string]
    to_row = to_cell.row
    to_col = to_cell.col_idx

    for row_num, row in enumerate(from_sheet[from_range_string]):
        if not row:
            continue

        # 行の高さをコピー
        to_row_dimension = to_sheet.row_dimensions[to_row + row_num]
        from_row_dimension = from_sheet.row_dimensions[row[0].row]
        to_row_dimension.height = from_row_dimension.height

        for col_num, cell in enumerate(row):
            to_cell = to_sheet.cell(row=to_row + row_num, column=to_col + col_num)

            # cellの値をコピー
            to_cell.value = cell.value

            # cellのスタイルをコピー
            if cell.has_style:
                to_cell._style = copy(cell._style)

row_dimensionもcopyできるんじゃないかと思うけど未確認です。
cellのスタイル以外も必要ならコピーすると良いと思う。

27
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
29