【業務自動化】Chapter2-4:ツールにエラー処理を追加しよう

ながみえ
本記事には広告(アフィリエイトリンク)が含まれます。リンク経由で申込が発生した場合、当サイトが報酬を受け取る可能性があります。

一つ前のページでは 表記ゆれ置換ツールをCSVに対応 するよう改造しました。

今回は エラー処理 を追加しましょう。

Chapter1:PythonでExcelを操作しよう
Chapter2:PyInstallerで自動化ツールを(.exe)作ろう
 ・Chapter2-1:Pythonスクリプトを実行ファイルに変換しよう
 ・Chapter2-2:表記ゆれを一瞬で直す置換マシンを作ろう
 ・Chapter2-3:置換の対象ファイルを増やそう
 ・Chapter2-4:エラー処理を追加しよう ◁今回はここ
 ・Chapter2-5:ダイアログウィンドウを追加しよう
Chapter3:便利な自動化ツールを5つ作ろう
Chapter4:Webスクレイピング入門
Chapter5:自動化ツールを作って稼ごう

業務自動化ツールを実際の業務で使うためには、「動けばいい」だけでは不十分です。

想定外のエラーが起きた時に処理が途中で止まってしまうと、作業効率を下げてしまったり、誤ったデータを保存してしまうリスクがあります。

そこで本記事では try/except を活用してツールにエラー処理を追加し、より堅牢で安心して使えるプログラムに仕上げる ことを目標とします。

前回までに作成した「表記ゆれの一斉置換ツール」に、実務に耐えられるエラーハンドリングを組み込みましょう。

あわせて読みたい
【Python】レッスン2-9:例外処理を理解しよう
【Python】レッスン2-9:例外処理を理解しよう

<<前のページ

業務自動化の記事一覧

次のページ>>

try/exceptで例外処理|Excel自動化ツールを安全に強化

これまでに作ったツールは正常な条件では問題なく動作しますが、例えば次のような状況ではエラーで強制終了してしまいます。

  • 必要なExcelファイルが存在しない
  • 編集対象のテキストファイルやCSVファイルが他のアプリで開かれている
  • 入力の途中で予期せぬ操作が行われた

こうした事態に備えて、try/except を使ってエラーが起きた際に「ユーザーにわかりやすいメッセージを表示し、安全に処理を続行または終了できるようにする」ことが大切です。

今回の学習で使用するxlsxファイルとtxtファイルを配布しますので、↓↓のダウンロードリンクをクリックして適切な場所に保存して下さい。

Q
ファイルの保存場所について

ダウンロードしたファイルは以下の階層になるように保存して下さい。

この理由については、Chapter2-1 の記事で詳しく解説しています。

Chap2/   					# チャプター2全体の保存フォルダ
│
├── Chap2-1/				# チャプター2-1の保存フォルダ
│   ├── Chapter2-1.py
│   ├── Workbooks/
│   │   └── Chapter2-1.xlsx
│   └── Chapter2-1.exe
│
├── Chap2-2/				# チャプター2-2の保存フォルダ
│   ├── Chapter2-2.py
│   ├── Workbooks/
│   │   └── Chapter2-2.xlsx
│   ├──texts/
│   │   └── サンプルテキスト.txt
│   └── Chapter2-1.exe
│
├── Chap2-3/
├── ・・・
【Python】勉強猫がノートパソコンを前にして学習を始める様子。記事内の学習スタート用イラスト

サンプルコード紹介|openpyxl+テキスト/CSV置換ツール

以下は、今回のチャプターで紹介するサンプルコードです。

前回の記事で作成した「表記ゆれの一斉置換ツール」に Excelファイルが存在しない場合のエラー処理 を追加したものです。

前回のコードとの相違点は次の章で解説するので、まずはコード全体をコピーして実行してみましょう。

import openpyxl     # xlsxを読み取るための外部モジュール
import pathlib      # ファイルやフォルダのパスを扱うための標準モジュール
import sys          # 実行環境を判定するために使用(py または exe)
import pyinputplus  # 入力値のチェックを行う外部モジュール
import csv          # CSVファイルを読み書きするための標準モジュール

# 実行環境に応じて基準ディレクトリを決定(exeかpyファイルか)
if getattr(sys, 'frozen', False):
    BASE_DIR = pathlib.Path(sys.executable).parent  # exe で動いている場合
else:
    BASE_DIR = pathlib.Path(__file__).parent        # pyファイルとして動いている場合
file_path = BASE_DIR / "workbooks"      # Excelファイルを格納するフォルダ
text_path = BASE_DIR / "input_files"    # 置換するファイルを格納するフォルダ

# 例外処理(Excelファイルが見つからない場合の処理)
try:
    book = openpyxl.load_workbook(file_path / "Chapter2-2.xlsx")
    sheet = book.active
except FileNotFoundError:
    print("置換リストがみつかりません")
    input("エンターキーでプログラムを閉じます")
    sys.exit(1)

# 置換するファイル形式を選択
file_type = pyinputplus.inputChoice(
    ["txt", "csv"],
    "置換するファイル形式を選択してください(txt/csv)")

# 置換リスト(Excelから読み込む検索語・置換語)の定義
READ_START_ROW_NO = 3   # データ読み込みを開始する行
OLD_WORD_COL_NO = 2     # 検索する文字列が書かれた列
NEW_WORD_COL_NO = 3     # 置換後の文字列が書かれた列
old_words = []          # 検索する文字列のリスト
new_words = []          # 置換後の文字列のリスト

# Excelから置換リストを読み込む
for i in range(READ_START_ROW_NO, sheet.max_row+1): # データが書かれた全ての行に対して
    old_word = sheet.cell(i, OLD_WORD_COL_NO).value # 検索語を読み取り
    if old_word is None:            # 検索語が空白なら
        break                       # 繰り返しを終了
    old_words.append(str(old_word)) # 検索語をリストに追加

    new_word = sheet.cell(i, NEW_WORD_COL_NO).value # 置換語を読み取り
    if new_word is None:            # 置換語が空白なら
        new_word = old_word         # 検索語をそのまま使う
    new_words.append(str(new_word)) # 置換語をリストに追加

# テキストファイルを処理
file_counter = 0
if file_type == "txt":
    for target_file in text_path.glob(f"*.{file_type}"): # フォルダ内の全てのテキストファイルに対して
        # 改行して置換開始の宣言
        print()
        print(f'{target_file.name}のテキストを置換します')
        # テキストファイルを読み込み、検索語を置換語に置き換え
        file_text = target_file.read_text(encoding = "UTF-8")
        for i in range(len(old_words)):
            file_text = file_text.replace(old_words[i], new_words[i])
        # 新しいファイルを作成
        new_file_path = target_file.parent / f"【表記ゆれ修正済み】{target_file.stem}.{file_type}"
        new_file_path.write_text(file_text, encoding="UTF-8")
        file_counter += 1

# CSVファイルを処理
elif file_type == "csv":
    for target_file in text_path.glob(f"*.{file_type}"):  # フォルダ内の全てのCSVファイルに対して
        print()
        print(f'{target_file.name}のCSVを置換します')
        # CSVを読み込む
        with open(target_file, newline='', encoding="utf-8-sig") as f:
            reader = csv.reader(f)
            rows = [row for row in reader]
        # セル単位で置換処理
        for i in range(len(old_words)):
            rows = [[cell.replace(old_words[i], new_words[i]) for cell in row] for row in rows]
        # 新しいCSVファイルを作成
        new_file_path = target_file.parent / f"【表記ゆれ修正済み】{target_file.stem}.{file_type}"
        with open(new_file_path, "w", newline='', encoding="utf-8-sig") as f:
            writer = csv.writer(f)
            writer.writerows(rows)
        file_counter += 1

# 改行して終了
print()
print(f'{file_counter}ファイル置換完了')
input("Enterキーでプログラムを終了します")

サンプルスクリプトの解説|例外処理の設計ポイント

このスクリプトのポイントを順を追って見ていきましょう。

過去の記事で解説した部分は簡潔に書いていますので、分からない場合は過去の記事へ移動して下さい。

必要なモジュールのインポート

import openpyxl     # xlsxを読み取るための外部モジュール
import pathlib      # ファイルやフォルダのパスを扱うための標準モジュール
import sys          # 実行環境を判定するために使用(py または exe)
import pyinputplus  # 入力値のチェックを行う外部モジュール
import csv          # CSVファイルを読み書きするための標準モジュール

ここでは、ツールの基盤となるモジュールを読み込んでいます。

この部分はツールの準備段階にあたり、後続の処理を安定させるために欠かせない要素です。

実行環境ごとに基準ディレクトリを設定する

# 実行環境に応じて基準ディレクトリを決定(exeかpyファイルか)
if getattr(sys, 'frozen', False):
    BASE_DIR = pathlib.Path(sys.executable).parent  # exe で動いている場合
else:
    BASE_DIR = pathlib.Path(__file__).parent        # pyファイルとして動いている場合
file_path = BASE_DIR / "workbooks"      # Excelファイルを格納するフォルダ
text_path = BASE_DIR / "input_files"    # 置換するファイルを格納するフォルダ

この部分では、プログラムの実行環境に応じて「基準となるフォルダ」を決めています。

そしてその基準フォルダを使って:

  • file_path:Excelの置換リストを保存している workbooks フォルダ
  • text_path:処理対象となるテキストやCSVを保存している input_files フォルダ

をそれぞれ指定しています。

この部分の詳細解説は Chapter2-1 の記事を参照してください。

【変更部分】Excel置換リストの読込エラーを処理|FileNotFoundError

# 例外処理(Excelファイルが見つからない場合の処理)
try:
    book = openpyxl.load_workbook(file_path / "Chapter2-2.xlsx")
    sheet = book.active
except FileNotFoundError:
    print("置換リストがみつかりません")
    input("エンターキーでプログラムを閉じます")
    sys.exit(1)

この部分は、今回のチャプターで新しく追加された「エラー処理」です。

Excelファイルが存在しなかったときに FileNotFoundError を検出し、ユーザーに原因をわかりやすく伝えます。

また、sys.exit(1) はプログラムを安全に終了するコードです。

引数の「1」は「エラー終了」であることを示しています。

あわせて読みたい
【Python】レッスン2-9:例外処理を理解しよう
【Python】レッスン2-9:例外処理を理解しよう

置換対象のファイル形式を選択する

# 置換するファイル形式を選択
file_type = pyinputplus.inputChoice(
    ["txt", "csv"],
    "置換するファイル形式を選択してください(txt/csv)")

ここでは、ユーザーに「どのファイル形式を処理するか」を選ばせています。

この部分の詳細解説は Chapter2-3 の記事を参照してください。

置換リストの定義

# 置換リスト(Excelから読み込む検索語・置換語)の定義
READ_START_ROW_NO = 3   # データ読み込みを開始する行
OLD_WORD_COL_NO = 2     # 検索する文字列が書かれた列
NEW_WORD_COL_NO = 3     # 置換後の文字列が書かれた列
old_words = []          # 検索する文字列のリスト
new_words = []          # 置換後の文字列のリスト

この部分では、Excelから置換リストを読み取るための「設定」と「空のリスト」を準備しています。

Excelから置換リストを読み込む

# Excelから置換リストを読み込む
for i in range(READ_START_ROW_NO, sheet.max_row+1): # データが書かれた全ての行に対して
    old_word = sheet.cell(i, OLD_WORD_COL_NO).value # 検索語を読み取り
    if old_word is None:            # 検索語が空白なら
        break                       # 繰り返しを終了
    old_words.append(str(old_word)) # 検索語をリストに追加

    new_word = sheet.cell(i, NEW_WORD_COL_NO).value # 置換語を読み取り
    if new_word is None:            # 置換語が空白なら
        new_word = old_word         # 検索語をそのまま使う
    new_words.append(str(new_word)) # 置換語をリストに追加

この処理では、Excelシートから「検索語」と「置換語」を1行ずつ読み込んで、リストに格納しています。

この部分の詳細解説は Chapter2-2 の記事を参照してください。

テキストファイルを処理する

# テキストファイルを処理
file_counter = 0
if file_type == "txt":
    for target_file in text_path.glob(f"*.{file_type}"): # フォルダ内の全てのテキストファイルに対して
        # 改行して置換開始の宣言
        print()
        print(f'{target_file.name}のテキストを置換します')
        # テキストファイルを読み込み、検索語を置換語に置き換え
        file_text = target_file.read_text(encoding = "UTF-8")
        for i in range(len(old_words)):
            file_text = file_text.replace(old_words[i], new_words[i])
        # 新しいファイルを作成
        new_file_path = target_file.parent / f"【表記ゆれ修正済み】{target_file.stem}.{file_type}"
        new_file_path.write_text(file_text, encoding="UTF-8")
        file_counter += 1

この処理では、選択されたファイル形式が txt の場合に対象フォルダ内のすべてのテキストファイルを処理します。

この部分の詳細解説は Chapter2-2 の記事を参照してください。

CSVファイルを処理する

# CSVファイルを処理
elif file_type == "csv":
    for target_file in text_path.glob(f"*.{file_type}"):  # フォルダ内の全てのCSVファイルに対して
        print()
        print(f'{target_file.name}のCSVを置換します')
        # CSVを読み込む
        with open(target_file, newline='', encoding="utf-8-sig") as f:
            reader = csv.reader(f)
            rows = [row for row in reader]
        # セル単位で置換処理
        for i in range(len(old_words)):
            rows = [[cell.replace(old_words[i], new_words[i]) for cell in row] for row in rows]
        # 新しいCSVファイルを作成
        new_file_path = target_file.parent / f"【表記ゆれ修正済み】{target_file.stem}.{file_type}"
        with open(new_file_path, "w", newline='', encoding="utf-8-sig") as f:
            writer = csv.writer(f)
            writer.writerows(rows)
        file_counter += 1

この処理では、CSVファイルを1つずつ開いて中身を置換し、新しいファイルを保存します。

この部分の詳細解説は Chapter2-3 の記事を参照してください。

終了処理と結果の表示

# 改行して終了
print()
print(f'{file_counter}ファイル置換完了')
input("Enterキーでプログラムを終了します")

ここでは、置換処理がすべて終わった後にユーザーへ結果を伝えています。

PyInstallerでエラー処理付きツールを完成させよう

これまでの手順で、置換リストが見つからない場合でも安全に終了できるようになりました。

最後にこれまで同様 PyInstallerで実行ファイル化 し、現場でそのまま使える形に仕上げましょう。

PyInstallerでツール化しよう

実務で使用するためには、Pythonのソースコードを毎回コマンドラインから実行するのではなく、誰でも簡単にダブルクリックで動かせる実行ファイル(exe形式) にしておきましょう。

この手順についてはすでに 過去の記事で解説済み なので、ここでの説明は省略します。

コマンドプロンプト以下のコードを実行してください。

pyinstaller --onefile Chapter2-4-1.py

これで、前回と同様にPythonをインストールしていないPCでも実行できるようになります。

作成されたexeファイルを適切な位置に移動させることを忘れないよう注意しましょう。

まとめ|try/exceptで堅牢なツールを作ろう

今回のチャプターでは、try/except を用いた基本的なエラー処理の追加 を学びました。

ポイントは以下の通りです。

  • try/except を使えば、予期せぬエラーが発生してもユーザーにメッセージを表示して安全に終了できる
  • 実務で使うツールにおいて「落ちない」仕組みは非常に重要

この後の練習問題ではこのエラー処理をさらに発展させて、ファイルの書き込み時にエラーが発生した場合の対処 を追加します。

これにより、さらに堅牢なツールへと進化させていきましょう。

練習問題|エラー処理を追加しよう

今回学習した内容を復習する練習問題に挑戦しましょう。

【Python】勉強猫がノートパソコンに向かい、練習問題に挑戦する様子。記事内の休憩用イラスト

問題|ファイル保存時のエラーを処理できるツールに改良しよう

この記事の前半で紹介したChapter2-4-1.pyは、テキストやCSVを処理中に対象ファイルが別のアプリで開かれていると、エラーでプログラムが停止してしまう問題がありました。

今回は、そのような状況でもプログラムが落ちずに処理を続けられるように改良しましょう。

以下の要件に従ってコードを完成させて下さい。

  • Chapter2-4-1.py をベースにコードを修正すること
  • 表記ゆれ修正後のファイルを上書き保存するように変更すること(新規作成しない)
  • 保存時に PermissionError が発生した場合 は、
    • エラーメッセージを表示する
    • そのファイルをスキップして次の処理を続行する

正解サンプルコード|PermissionError対応

例えば以下のようなプログラムが考えられます。

Q
正解コード例
import openpyxl     # xlsxを読み取るための外部モジュール
import pathlib      # ファイルやフォルダのパスを扱うための標準モジュール
import sys          # 実行環境を判定するために使用(py または exe)
import pyinputplus  # 入力値のチェックを行う外部モジュール
import csv          # CSVファイルを読み書きするための標準モジュール

# 実行環境に応じて基準ディレクトリを決定(exeかpyファイルか)
if getattr(sys, 'frozen', False):
    BASE_DIR = pathlib.Path(sys.executable).parent  # exe で動いている場合
else:
    BASE_DIR = pathlib.Path(__file__).parent        # pyファイルとして動いている場合
file_path = BASE_DIR / "workbooks"      # Excelファイルを格納するフォルダ
text_path = BASE_DIR / "input_files"    # 置換するファイルを格納するフォルダ

# 例外処理(Excelファイルが見つからない場合の処理)
try:
    book = openpyxl.load_workbook(file_path / "Chapter2-2.xlsx")
    sheet = book.active
except FileNotFoundError:
    print("置換リストがみつかりません")
    input("エンターキーでプログラムを閉じます")
    sys.exit(1)

# 置換するファイル形式を選択
file_type = pyinputplus.inputChoice(
    ["txt", "csv"],
    "置換するファイル形式を選択してください(txt/csv)")

# 置換リスト(Excelから読み込む検索語・置換語)の定義
READ_START_ROW_NO = 3   # データ読み込みを開始する行
OLD_WORD_COL_NO = 2     # 検索する文字列が書かれた列
NEW_WORD_COL_NO = 3     # 置換後の文字列が書かれた列
old_words = []          # 検索する文字列のリスト
new_words = []          # 置換後の文字列のリスト

# Excelから置換リストを読み込む
for i in range(READ_START_ROW_NO, sheet.max_row+1): # データが書かれた全ての行に対して
    old_word = sheet.cell(i, OLD_WORD_COL_NO).value # 検索語を読み取り
    if old_word is None:            # 検索語が空白なら
        break                       # 繰り返しを終了
    old_words.append(str(old_word)) # 検索語をリストに追加

    new_word = sheet.cell(i, NEW_WORD_COL_NO).value # 置換語を読み取り
    if new_word is None:            # 置換語が空白なら
        new_word = old_word         # 検索語をそのまま使う
    new_words.append(str(new_word)) # 置換語をリストに追加


# テキストファイルを処理
file_counter = 0
if file_type == "txt":
    for target_file in text_path.glob(f"*.{file_type}"): # フォルダ内の全てのテキストファイルに対して
        # 改行して置換開始の宣言
        print()
        print(f'{target_file.name}のテキストを置換します')
        # テキストファイルを読み込み、検索語を置換語に置き換え
        file_text = target_file.read_text(encoding = "UTF-8")
        for i in range(len(old_words)):
            file_text = file_text.replace(old_words[i], new_words[i])
        # 上書き保存
        try:
            target_file.write_text(file_text, encoding="UTF-8")
            file_counter += 1
        except PermissionError:
            print(f"{target_file.name} に書き込みできません(他で開いている可能性があります)")
        continue  # このファイルを飛ばして処理を続ける

# CSVファイルを処理
elif file_type == "csv":
    for target_file in text_path.glob(f"*.{file_type}"):  # フォルダ内の全てのCSVファイルに対して
        print()
        print(f'{target_file.name}のCSVを置換します')
        # CSVを読み込む
        with open(target_file, newline='', encoding="utf-8-sig") as f:
            reader = csv.reader(f)
            rows = [row for row in reader]
        # セル単位で置換処理
        for i in range(len(old_words)):
            rows = [[cell.replace(old_words[i], new_words[i]) for cell in row] for row in rows]
        # 上書き保存
        try:
            with open(target_file, "w", newline='', encoding="utf-8-sig") as f:
                writer = csv.writer(f)
                writer.writerows(rows)
            file_counter += 1
        except PermissionError:
            print(f"{target_file.name} に書き込みできません(他で開いている可能性があります)")
            continue

# 改行して終了
print()
print(f'{file_counter}ファイル置換完了')
input("Enterキーでプログラムを終了します")
もっと分かりやすい学習サイトにするために

この記事を読んで「ここが分かりにくかった」「ここが難しかった」等の意見を募集しています。

世界一わかりやすいExcel自動化学習サイトにするため、ぜひ 問い合わせフォーム からご意見下さい。

<<前のページ

業務自動化の記事一覧

次のページ>>

次のステップ:業務自動化を「実務レベル」まで引き上げたい方へ

このコース(Chapter1〜2)の無料教材では、Python と Excel(openpyxl)を使って「単純作業を自動化する」ための基本的な考え方やコードの書き方を身につけることができます。

ただ、実際の業務で使おうとすると、次のような壁にぶつかりがちです。

  • 社内で使える「ちゃんとしたツール」っぽい形にしたい
  • エラーが出たときに、自分で原因を特定して直せない
  • 副業したくても本当に正しく動くか自信がない

そこで、格安で販売中のChapter3以降では「現場でそのまま使える業務自動化スクリプト」を作りながら学べる構成としました。

そこでは、Chapter2までで学んだ内容を土台にしつつ、

  • 実務でよくあるパターン別のサンプルコード
  • トラブルシューティング(エラーの潰し方)の考え方
  • より高度な自動化を実現するWebスクレイピングの基本
  • 業務自動化スキルを用いて副業で稼ぐための具体的な方法

などを通して、「自分の職場に合わせてカスタマイズできる力」を身につけることを目指します。

教材は↓↓のリンクボタンの販売所で購入するとPDFやpyファイルでダウンロードできます。

もしくは、各学習記事内で会員登録して頂くと、そのままこのサイト内で全ての記事を読めるようになります。

どこよりも安く手実践的なこの教材を、是非ご活用下さい^^

記事URLをコピーしました