質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.59%

ファイル内のExcelシートに同一処理(書式変更等)を行いたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 169

score 2

最近pythonを勉強し始めた初心者です。見ていただき、ありがとうございます。

openpyxlでファイルに入っている全てのExcelファイルに同一の処理をするための方法を考えているのですが、
一つずつ処理をしていくコードの書き方がわからず困っております。
一つのExcelファイルを同じフォントにしたり、色の調整、枠を引く作業のコードはかけたのですが、最後のファイルの処理の部分がうまくいっておりません。(下のコードはフォント変更のコードを載せています)

一つのファイルに100ほど同じフォントにしたいExcelファイルがあるので、
一括で全てのファイルの書式が変更できるようにしたいと考えております。

お知恵を拝借できると幸いです。
よろしくお願いいたします。

!pip install openpyxl
import openpyxl 
from openpyxl.styles import Font
import pandas as pd
from glob import glob

filepaths = glob('ファイルが保存されている場所')
filepath = filepaths[0] #恥ずかしながら、ここの数値を手動で変えて今回は作業していました。
df = pd.read_excel(filepath) #ファイルの読み込み
export_file = 'excel000.xlsx' #保存先
df.to_excel(export_file) #Excelへの書き込み
#もとのExcelファイルをpythonに読み込んで、修正したExcelに保存する形をとっています。

workbook = openpyxl.load_workbook(export_file) #ワークブックの読み込み
worksheet = workbook.worksheets[0] #ワークシートの指定

font = Font(name='メイリオ',size=9) #フォントの変更とフォントサイズの変更
sheet_range =worksheet['A1':'M100'] #変更する範囲

for row in sheet_range:
    for cell in row:
        worksheet[cell.coordinate].font = font #それぞれのセルのフォントを変更

workbook.save(export_file) #修正したものを保存

今回は上述のコードのfilepaths[0]の部分の数値とexport_file = 'excel000.xlsx' #保存先の値を変えて、手動で処理を行っていましたが、一括で全てのファイルのフォントを変更したいです。

どうぞよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

Pythonではfor文で繰り返し処理ができます。

for filepath in filepaths:
    print(filepath)
    export_file = 'export_' + filepath  # export_ファイル名.xlsx
    print(export_file)

連番を振る必要があるなら enumerate() を使えます。

for idx, filepath in enumerate(filepaths):
    print(filepath)
    export_file = filepath.replace(".xlsx", f"_{idx:03}.xlsx")  # ファイル名_000.xlsx
    print(export_file)

書き出し用のフォルダを作っておいてそこに元と同じファイル名で保存する方法もあります。

for filepath in filepaths:
    print(filepath)
    export_file = 'export/' + filepath  # exportフォルダに保存(Windowsだと 'export\' かも)
    print(export_file)

df = pd.read_excel(filepath) と df.to_excel(export_file) は不要ではないでしょうか。

for filepath in filepaths:
    workbook = openpyxl.load_workbook(filepath)
    # ...
    # workbookに対する処理を行う
    # ...
    export_file = 'export_' + filepath
    workbook.save(export_file)

追記:glob のパス指定で絶対パスを使用した場合

glob のパス指定で、'C:\\Users\\Tanaka\\Documents\\checksheet\\*.xlsx' といった 'C:\' から始まるパスを指定した場合は、絶対パスで指定したことになります(これに対して、相対パスで指定する方法もありますが、ここでは詳細は省きます)。

絶対パスを使用した場合は、取得されるファイルのパスも絶対パスになりますので、このパスを加工する場合は、ファイル名とディレクトリパスに分割してから処理するのがやりやすいです。

以下は簡単なサンプルコードです。

from glob import glob
import os

filepaths = glob('C:\\Users\\Tanaka\\Documents\\checksheet\\*.xlsx')
for filepath in filepaths:
        # 取得されるファイルのパスは絶対パス
        print(filepath)  # => C:\Users\Tanaka\Documents\checksheet\xxxx.xlsx
        # 絶対パスからファイル名のみを取り出す
    filename = os.path.basename(filepath)
    print(filename)  # => xxxx.xlsx
        # 絶対パスからファイル名を除いたディレクトリパスの部分だけを取り出す
    dirname = os.path.dirname(filepath)
    print(dirname)  # => C:\Users\Tanaka\Documents\checksheet
        # ファイル名とディレクトリパスを結合して再度ファイルの絶対パスを作成する
    new_path = os.path.join(dirname, filename)
    print(new_path)  # => C:\Users\Tanaka\Documents\checksheet\xxxx.xlsx
    print()

    # 次のようにしてファイル名とディレクトリパスを一度に取得してもよい
    dirname, filename = os.path.split(filepath)

以下簡単に説明します。

ファイル名とディレクトリパスに分割するには 
os.path.basename と os.path.dirname を使います。もしくは os.path.split を使います。

filename = os.path.basename(filepath)
dirname = os.path.dirname(filepath)

# もしくは
dirname, filename = os.path.split(filepath)

分割した後に、取得したファイル名とディレクトリパスを、書き出すファイルはどんなファイル名で、どこのディレクトリに保存したいかに合わせて加工します。
同じファイル名やディレクトリパスでよければそのままでもいいです。

加工し終わったら、加工済みのファイル名とディレクトリパスを os.path.join を使って結合して、最終的な書き出し用パスを得ます。

new_path = os.path.join(dirname, filename)

以下に具体的な例をいくつか挙げます。

書き出しファイル名に共通の接頭辞(ここでは'export_')をつけて同じフォルダに保存する場合:

for filepath in filepaths:
    dirname, filename = os.path.split(filepath)
    new_filename = 'export_' + filename  # ファイル名を加工
    export_filepath = os.path.join(dirname, new_filename)
    print(export_filepath)

書き出しファイル名に連番を振って同じフォルダに保存する場合:

for idx, filepath in enumerate(filepaths):
    dirname, filename = os.path.split(filepath)
    new_filename = filename.replace(".xlsx", f"_{idx:03}.xlsx")  # ファイル名を加工
    export_filepath = os.path.join(dirname, new_filename)
    print(export_filepath)

書き出し用のフォルダ(ここでは 'export')を作ってそこに元と同じファイル名で保存する場合:

# 書き出し用のフォルダを元のフォルダの中に作った場合
for filepath in filepaths:
    dirname, filename = os.path.split(filepath)
    new_dirname = os.path.join(dirname, 'export')  # 元のフォルダ + exportフォルダ
    export_filepath = os.path.join(new_dirname, filename)
    print(export_filepath)

# 書き出し用のフォルダを元のフォルダと同じ階層に作った場合
for filepath in filepaths:
    dirname, filename = os.path.split(filepath)
    upper_dirname = os.path.dirname(dirname)  # 元のフォルダのひとつ上の階層のパスを取得
    new_dirname = os.path.join(upper_dirname, 'export')  # ひとつ上の階層 + exportフォルダ
    export_filepath = os.path.join(new_dirname, filename)
    print(export_filepath)

なお、raw文字列(r'xxx')を使うと、その文字列内のエスケープ ('\') は、エスケープとしての特別な機能を失ってただの文字列になります。そのため下記のコードは、

filepaths = glob('C:\\Users\\Tanaka\\Documents\\checksheet\\*.xlsx')


raw文字列を使って次のように書くこともできます。

filepaths = glob(r'C:\Users\Tanaka\Documents\checksheet\*.xlsx')

os.getcwd() はカレントディレクトリを確認するためのコードです。
相対パスを使用する場合は、カレントディレクトリを把握しておくことが重要になりますが、今回質問者さんは絶対パスを使用されていましたので、説明は省略させていただきます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/07/12 11:48

    ご回答いただき、ありがとうございます。
    早速、ご確認いただたいた点を記載させていただきます。

    >コードの
    >filepaths = glob('ファイルが保存されている場所')
    >の「ファイルが保存されている場所」の箇所に実際に入力されている文字列を教えてください。

    filepaths = glob('C:\\Users\\Tanaka\\Documents\\checksheet\\*.xlsx')
    #ユーザー名はTanakaではありませんが、このような姓をアルファベットで表記したものがはいっています。

    >for filepath in filepaths:
    >print(filepath)
    >の出力結果を途中まで(3行程度)でいいので教えてください。

    C:\Users\Tanaka\Documents\checksheet\ファイル名(日本語).xlsx
    C:\Users\Tanaka\Documents\checksheet\ファイル名(日本語).xlsx
    C:\Users\Tanaka\Documents\checksheet_outC:\Users\Tanaka\Documents\checksheet\ファイル名(日本語).xlsx
    ※ファイル名は、取引先等が含まれるので伏字にさせていただいています。すべて、ひらがなと漢字の組み合わせの名前をつけて、記号は使用していません。
     出力されるものはこの3行のみで、そのすぐ下に背景が赤くなったエラーメッセージ群がでてきています。

    >import os
    >print('cwd: ', os.getcwd())

    >の2行をコードのどこでもいいので追加していただいて、表示される「cwd: 〜」という文字列の内容を
    >教えてください。ユーザ名などは伏せ字でいいです。

    cwd: C:\Users\Tanaka\Training\フォルダー名
    ※JupyterLabを使って処理をしています。フォルダー名は、JupyterLab内に作成しているファルダ―名です。アルファベット表記になり、日本語(ひらがな・漢字・カタカナ)は使用していません。


    お時間いただき、ご回答くださいまして、本当にありがとうございます。
    どうぞよろしくお願いいたします。

    キャンセル

  • 2021/07/12 16:44

    ありがとうございます。
    普段自分が相対パスを多用しているために、質問者さんも相対パスを使用しているものと勝手に思い込んで回答してしまいました。そのため不完全な回答になってしまっていました。申し訳ありません。
    回答に追記させていただきました。

    キャンセル

  • 2021/07/14 18:49

    ご丁寧なご回答ありがとうございました。

    おかげさまで、目的としていたプログラムを作成することができました。
    また、相対パスと絶対パスについても教えていただきありがとうございました。
    しっかり理解できていないところでしたので、改めて勉強しなおしたいと思います。
    貴重な経験となりました。

    また、いろいろとご質問させていた際は、ご教授いただけますと幸いです。
    どうぞよろしくお願いいたします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る