背景
社内で利用してよさそうなツールがなかったためpythonでツールを自作。
import os
import warnings
import pandas as pd
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import Scrollbar, Text
def generate_excel_columns(num_columns):
"""
どこの列に記載されているか表示したいが、
A列のような取得方法が不明であったためA列からXFD列分配列を生成
"""
columns = []
col = 0
while len(columns) < num_columns:
col_str = ""
temp_col = col
while temp_col >= 0:
col_str = chr(temp_col % 26 + ord('A')) + col_str
temp_col = temp_col // 26 - 1
columns.append(col_str)
col += 1
return columns
def out_put_text_search(text, folders, files, result_text_widget):
# エクセル出力用変数
out_folder_name = []
out_file_name = []
out_keys = []
out_colums = []
out_rows = []
out_display = []
num_columns = 16384 # 生成する列数
excel_columns = generate_excel_columns(num_columns)
result_text_widget.insert(tk.END, f"検索対象ファイル\n")
for index in range(len(folders)):
if '~$' not in files[index] and ('.xlsx' in files[index] or '.xls' in files[index]):
file_path = os.path.join(folders[index], files[index])
#検索対象ファイルを表示
result_text_widget.insert(tk.END, f"{files[index]}\n")
try:
if files[index].lower().endswith('.xlsx'):
df = pd.read_excel(file_path, sheet_name=None,header=None, engine='openpyxl')
else: # .xlsファイルの場合
df = pd.read_excel(file_path, sheet_name=None,header=None, engine='xlrd')
for key in df.keys(): #シートの名前
sheet_df = df[key]
if sheet_df is not None and not sheet_df.empty:
for colum in sheet_df.columns:
column_data = sheet_df[colum]
if column_data is not None:
for row in range(len(column_data)):
cell_value = column_data.iloc[row]
if text in str(cell_value):
temp_out_folder_name = ""
temp_out_file_name = ""
temp_out_keys = ""
temp_out_colums = ""
temp_out_rows = ""
temp_out_display = ""
try:
temp_out_folder_name = folders[index]
temp_out_file_name = files[index]
temp_out_colums = excel_columns[colum]
temp_out_keys = key
temp_out_rows = str(row + 1)
temp_out_display = str(cell_value)
except Exception as e:
try:
temp_out_folder_name = folders[index]
temp_out_file_name = files[index]
temp_out_colums = colum
temp_out_keys = key
temp_out_rows = str(row + 2)
temp_out_display = str(cell_value)
except Exception as e:
result_text_widget.insert(tk.END, f"検索エラー: {str(e)}\n")
out_folder_name.append(temp_out_folder_name)
out_file_name.append(temp_out_file_name)
out_keys.append(temp_out_keys)
out_colums.append(temp_out_colums)
out_rows.append(temp_out_rows)
out_display.append(temp_out_display)
except Exception as e:
result_text_widget.insert(tk.END, f"ファイル読み込みエラー ({files[index]}): {str(e)}\n")
continue
# エクセルファイル出力用辞書
data = {
'フォルダ名':out_folder_name,
'ファイル名': out_file_name,
'シート名': out_keys,
'列': out_colums,
'行': out_rows,
'表示名': out_display
}
# データフレームを作成
out_df = pd.DataFrame(data)
file_path = os.getcwd() + f'/result_{text}.xlsx'
#書き込み
try:
out_df.to_excel(file_path, index=False, engine='openpyxl')
result_text_widget.insert(tk.END, '検索結果が Excel ファイル result.xlsx に保存されました。\n')
messagebox.showinfo("成功", "検索結果が保存されました。")
return file_path
except Exception as e:
result_text_widget.insert(tk.END, f"異常終了:{str(e)}\n")
messagebox.showerror("エラー", f"ファイル書き込みエラー: {str(e)}")
return None
def browse_folder(entry):
folder_path = filedialog.askdirectory()
if folder_path:
entry.delete(0, tk.END)
entry.insert(0, folder_path)
def start_search(text_entry, folder_entry, result_text_widget):
text = text_entry.get()
folder_path = folder_entry.get()
if not text or not folder_path:
messagebox.showerror("エラー", "検索文字列とフォルダパスを入力してください。")
return
if os.path.isdir(folder_path):
result_text_widget.delete(1.0, tk.END) # 既存の結果を消去
excel_folders = []
excel_files = [] # フォルダパスとファイル名を格納するリスト
for root, _, files in os.walk(folder_path): # 再帰的にフォルダを探索
for file in files:
if file.lower().endswith(".xlsx") or file.lower().endswith(".xls"): # .xlsx,xlsファイルをチェック
excel_folders.append(root)
excel_files.append(file)
output_file = out_put_text_search(text, excel_folders, excel_files, result_text_widget)
if output_file:
# 既存のボタンを削除して、新しいボタンを作成
for widget in open_button_frame.winfo_children():
widget.destroy()
open_button = tk.Button(open_button_frame, text=f"検索結果を開く ({text})", command=lambda: open_excel(output_file))
open_button.pack(pady=5)
else:
messagebox.showerror("エラー", "指定されたパスはディレクトリではありません。")
def open_excel(file_path):
#ファイルを開く
if os.name == 'nt':
os.startfile(file_path)
else:
messagebox.showerror("エラー", "windows以外はサポートしてないよ。")
warnings.filterwarnings("ignore")
# GUIの設定
root = tk.Tk()
root.title("Excelファイル検索ツール")
# ウィンドウサイズ
root.geometry("600x400")
# 検索文字列入力
tk.Label(root, text="検索したい文字列:").pack(pady=5)
text_entry = tk.Entry(root, width=50)
text_entry.pack(pady=5)
# フォルダパス入力
tk.Label(root, text="検索対象フォルダ:").pack(pady=5)
folder_entry = tk.Entry(root, width=50)
folder_entry.pack(pady=5)
folder_browse_button = tk.Button(root, text="フォルダ選択", command=lambda: browse_folder(folder_entry))
folder_browse_button.pack(pady=5)
# 結果表示用のテキストウィジェット
result_text_widget = Text(root, height=10, width=150)
result_text_widget.pack(pady=10)
result_text_widget.insert(tk.END, f"指定したフォルダ配下の全てのxlsx/xlsファイルが対象\n")
result_text_widget.insert(tk.END, f"フォルダ、ファイルの件数が多い場合実行時間が長くなるよ")
# スクロールバー追加
scrollbar = Scrollbar(root, command=result_text_widget.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
result_text_widget.config(yscrollcommand=scrollbar.set)
# 検索ボタン
search_button = tk.Button(root, text="検索", command=lambda: start_search(text_entry, folder_entry, result_text_widget))
search_button.pack(pady=10)
# 結果を開くボタン用のフレーム
open_button_frame = tk.Frame(root)
open_button_frame.pack(pady=0)
# メインループ
root.mainloop()
結果
課題
- 実行速度が遅い
各ファイルの各シートの行列分ループしてればそら遅いですよね
現状利用するのに困らないので時間が空いた時にでも検討したい

