テキストエディタのGrep機能感覚で、複数Excelファイルから手軽に文字列検索するツールを作成したので、その実装方法をご紹介します。
背景
- 複数Excel検索の一括検索をするシーンが多い
- 仕様の調査
- 設計書のレビュー
- 過去議事録の読み返し
- 多くのサンプルソースが公開されているが、自分好みのものを特定、選別するのが大変
- AIを使って自分で好みのツールを作った方が速い
スケジュールがタイトで短時間で多くのレビューをこなさなくてはならず困っていました
ウォーターフォール開発はレビュー品質を高めることで防げる手戻りや障害が沢山あるのです
ツールの要件
- 検索対象Excelファイル数が多くても、レスポンスが速い(重要要件)
- 検索対象指定フォルダを複数指定できる
- 検索対象指定したフォルダのサブフォルダも検索対象に含める
- 検索結果をTxtファイルに保存できる
(同じキーワードで検索しなくて済むよう、TxtファイルをRenameして保存する意図)
動作環境はWindows11、Python 3.12、Excel2021
ツールの実装
機能検討
- 検索対象パスは外部ファイル「Search.txt」から読ませる
# 検索対象パス
C:\Users\USER\hogePj\10.管理
C:\Users\USER\hogePj\20.要件定義
C:\Users\USER\hogePj\30.基本設計
# 検索文字列
顧客ID
-
処理結果は「Result.txt」に出力
SakuraエディタなどのGrep機能に近いイメージでOK。 -
「Search.txt」、「Result.txt」ともに、pythonプログラムのある同フォルダに配置
実装準備
ライブラリOpenPyXl1をインストールしよう。
下記コマンドを実行すればOK。
pip install pandas openpyxl
OpenPyXL公式リファレンス
実装方法
コーディングはChatGPTに任せて、要件の検討と意思決定に注力。
- ChatGPTに要件を伝えて、「pythonでソース書いて下さい」と入力
- ChatGPTが出力したソースを、VSCodeに貼り付けて実行してみる
- 改良要件を「〇〇の部分を✕✕するように修正してください」と入力
- 自分の意図通りの動作になるまで、2~3を繰り返す
実行エラーも「xx行目の変数hogehogeでint型変換エラーが発生しています。明示的にxxするよう修正して下さい」のように入力すればOK。
完成したソース
import os
import pandas as pd
def search_in_excel(folder_paths, search_string):
results = []
# 指定された各フォルダを処理
for folder_path in folder_paths:
# フォルダ内の全Excelファイルを取得(サブフォルダ含む)
for dirpath, _, filenames in os.walk(folder_path):
for filename in filenames:
# "~$"で始まるファイルを除外
if filename.startswith("~$"):
continue
if filename.endswith(('.xlsx', '.xls', '.xlsm')):
file_path = os.path.join(dirpath, filename)
try:
# Excelファイルを全てのシートを読み込む
df = pd.read_excel(file_path, sheet_name=None, header=None)
for sheet_name, sheet_data in df.items():
# 各シート内のセルを検索
for row_index in range(sheet_data.shape[0]): # 行をループ
for col_index in range(sheet_data.shape[1]): # 列をループ
cell = sheet_data.iloc[row_index, col_index] # 行と列のインデックスでセルを取得
# 検索対象の文字列が含まれているか確認
if isinstance(cell, str) and search_string in cell:
results.append((file_path, sheet_name, (row_index, col_index), cell))
except Exception as e:
print(f"Error reading {file_path}: {e}")
return results
def read_search_config(file_path):
folder_paths = []
search_string = ""
with open(file_path, 'r', encoding='utf-8') as f:
current_section = None
for line in f:
line = line.strip()
if not line:
continue
if line == "# 検索対象パス":
current_section = "folder_paths"
elif line == "# 検索文字列":
current_section = "search_string"
elif current_section == "folder_paths":
folder_paths.append(line)
elif current_section == "search_string":
search_string = line
return folder_paths, search_string
# Pythonスクリプトが存在するディレクトリを取得
script_dir = os.path.dirname(os.path.abspath(__file__))
# Search.txtから設定を読み込む
search_config_path = os.path.join(script_dir, 'Search.txt')
folder_paths, search_string = read_search_config(search_config_path)
# 検索を実行
results = search_in_excel(folder_paths, search_string)
# 結果をファイルに出力
output_file_path = os.path.join(script_dir, 'result.txt')
with open(output_file_path, 'w', encoding='utf-8') as file:
file.write(f"search_keyword: {search_string}\n")
for result in results:
file_path, sheet_name, (row_index, col_index), cell_value = result
file.write(f"Found in {file_path} -> {sheet_name} (Row: {row_index+1}, Col: {col_index+1}) - Value: {cell_value}\n")
print(f"Results have been written to {output_file_path}")
ChatGPT様、ありがとうございます。コメントも親切で、解読性が高くデバッグしやすい。
実行の様子
1.Search.txtを用意
2.pythonを実行
3.result.txtが生成される
4.実際のExcelの中身と、検索Hitしたセル位置の出力内夜が一致していることも確認済み。
以上で、簡単な動作確認が完了。
ファイル数を増やして、処理速度性能を試した
- Excelファイルが40~100個程度あるフォルダを4つ指定
- 検索実行の結果、100か所近くHit
実行時間は2分程度
さいごに
- pythonのExcel操作はシンプル、VBAで同ツールを作るより処理速度は高い
- 普段はコーディングしておらず、pythonの細かい文法を忘れてる私でも爆速でツールが完成した
- 実行エラーやこちらの意図と違う動作はあるため、ソースが読めて原因の行や理由を特定する勘所は必要(そこさえできれば、ChatGPTに修正を依頼するだけ)
- 皆さんもChatGPTで自分好みのツールを作って、生産性アップにチャレンジしてみよう
番外編(おまけの豆知識)
Win+Shift+Sだと右クリックメニューを表示したままのスクショが取れない💦
そんな悩みに遭遇したことがある方へ
私も本記事のアニメーションGifを作成するときに一瞬はまって、下記で解決しました
右クリックメニューを表示した状態でスクリーンショットを取る方法
Ctrl + PrintScreen
-
OpenPyXl:PythonでExcelファイルを読み書きするためのライブラリ ↩