CSV/Excel の行フィルターGUIツールをつくってみた

ども、平社員リョーマです。

最近ますますサックは元気いっぱい。
こないだ散歩中に、パラコードで手作りしたロングリードをつけて走らせてたら、
勢いあまりすぎて ロープじゃなくて金具のほうがボキッ… と折れてしまいました(´;ω;`)
数時間かけて編んだやつが、一瞬でただのヒモに…。
「市販のちゃんとしたやつ買うか… いや、また手作りするか…」と悩みつつ、
とりあえず今日はワンコではなく、人間用の作業効率化ツールの話を。


何を作ったか(ざっくり)

お店やECの仕事をしていると、定期的にやってくるのが

  • このカテゴリーの商品だけ一括で抜き出したい
  • このブランド群だけ別ファイルに分けたい
  • 一部の商品説明だけ手作業で直して、まとめてアップロードしたい

みたいな、一括処理のための「下準備」作業です。

やっていること自体はシンプルで、

  1. 商品CSV全体から、カテゴリやブランドなどで「対象商品だけ」を抜き出す
  2. その絞り込んだデータをもとに、商品説明などをチマチマ手作業で修正
  3. 修正後のCSVを、一括アップロード用として使う

これ、Excel のフィルター機能でも一応できるんですが、

  • CSV のレコード数が多くなると、そもそも開くのに時間がかかる
  • フィルター条件を変えるたびに「チェックを付け直し → 適用 → また外す」を繰り返す必要がある
  • 「いらないグループを一気に消す」「必要なグループだけ残す」といった操作を、もう少し視覚的にやりたい

というストレスがじわじわ溜まってきます。

そこで、

「先に pandas で、必要な行だけ抜き出して『軽いCSV』にしておいたほうが早いよね?」 ってもともと思っていたけど後回しに来て 我慢の限界に到達(笑) サクッとできるのになぜ後回しに…..(´;ω;`)

という発想で作ったのが、今回の CSV/Excel 専用「行フィルター GUI ツール」 です。

今の v1 では「列の値ベースでの絞り込み」がメインですが、今後は

  • キーワードでの絞り込み(商品名や型番や説明文で検索して絞る)

なども追加して、v2 として育てていく予定です。
とはいえ、そこは時間があるときにゆっくりでいいかな、という感じで、
まずは「Excel フィルターの前に軽く前処理するツール」として動くところまで仕上げています。


できること(ユーザー視点の機能まとめ)

このツールでできることを、ユーザー視点でざっくり並べるとこんな感じです。

  • CSV または Excel ファイルを選択して読み込み
    • 文字コードは自動判定(UTF-8 / CP932 / EUC-JP など、日本でよくあるものをカバー)
    • 区切り文字もカンマ、タブ、セミコロンなどを順番にトライ
  • pandas で DataFrame に変換
  • 任意の「列(ヘッダー)」を選択
  • その列に含まれる 値ごとに行をグループ化
    • 同じ値を持つ行はひとまとまりに
    • 「◯◯(123件)」のように、件数付きで一覧表示
    • 値の一覧は、縦一列ではなく3列グリッド表示で見やすく配置
  • グループ単位で複数選択
    • クリックで ON/OFF(もう一度クリックで解除)
    • Shift+クリックで範囲選択も可能
  • 選んだグループに属する行を
    • 「削除する」(選んだ値の行だけ除外)
    • 「残す」(選んだ値の行だけを残して他を捨てる)
  • 最後に、元ファイルと同じ形式(CSV or Excel)で保存

実際の使い方としては、例えば:

  1. 「ブランド名」の列を選ぶ
  2. 値一覧から「このブランドは一旦全部抜きたい」というものをポチポチ選ぶ
  3. 「削除する」を選んで保存する

これだけで、特定ブランドだけを一気に除外したCSV ができるので、
あとは残ったデータに対して、商品説明の修正や価格調整などを集中して行えます。


ツールのコンセプトと設計のポイント

このツールは、最初から「どこか1つのモールだけに特化したもの」ではなく、 どのECの全商品CSVでも使える汎用ツールとして設計しています。

設計上、特に意識したポイントはこのあたりです。

  • モール非依存
    • 列名やレイアウトに強く依存しない
    • 「どの列を使って絞り込むか」はユーザーが選ぶ
  • GUIとロジックの分離
    • CustomTkinter を使った画面部分は GUI 用モジュールに閉じ込める
    • 行のグループ化やフィルター処理は、純粋な Python ロジックとして別モジュールへ分離
    • 将来 FastAPI 版を作るときに、そのままロジックだけ再利用できる構造にしておく
  • 文字コードの自動判定
    • 毎回「UTF-8で開く?SJISで開く?」と悩みたくない
    • 先頭のバイト列だけを読んで、chardet があればそれを活用
    • 判定が微妙でも、よく使う日本語エンコード(UTF-8 / CP932 / EUC-JP)を順番に試す
  • グループ単位で考えるUI
    • 1行ずつチェックボックスを付けるのではなく、「同じ値を持つ行まとめて扱う」
    • 「ブランド名 × 件数」をざっと眺めてから、どれを残すか決められる
  • Python をインストールしていない環境でも利用できます
    • ZIP を展開すると、フォルダが1つ作成されます
    • その中にある EXE ファイルをダブルクリックするだけで起動します(インストール不要)
    • 特別な設定やインストール作業は必要ありません
    • ブログからダウンロードして、すぐに試せる形にしています

なぜここまでモジュール分割しているのか

今回のツールは、正直「自分用に動けばOK」の世界なんですが、あえて最初からモジュールに分けています。
理由はいくつかあって、ざっくりまとめるとこんな感じです。

  • UIを差し替えやすくしておきたい
    • 今は CustomTkinter でGUIですが、将来 FastAPI でWeb版を作りたくなるかもしれない
    • そのときに「ロジックごと全部書き直し」になるのはもったいないので、最初から encoding_utils.py / data_io.py / row_filter_logic.py に 処理を寄せておく
    • GUI側(gui_row_filter_app.py)は「見た目とイベント処理」だけにしておくイメージ
  • CLI やバッチ処理にも流用しやすくするため
    • 将来「GUIなしで、コマンドラインからサクッと一括処理したい」というケースが出てくるかもしれない
    • そのときは、row_filter_logic.pydata_io.py をそのまま使って 「行フィルターCLI版」を作ればよいだけになる
    • GUIにべったりな設計だと、毎回ロジックを引きはがすところからスタートになるので、最初に分けておくほうがトク
  • テストとデバッグを楽にしたい
    • 「ファイル読み込み」「エンコード判定」「行フィルター処理」などを別モジュールにしておくと、 GUIを起動しなくても、Python の対話モードやテストコードから単体で動作確認できる
    • バグが出たときも「GUIのせいなのか、ロジックのせいなのか」が切り分けやすい
  • 未来の自分が迷子にならないようにするため
    • 1年後くらいにコードを開いたとき、「この巨大な1ファイル何してたっけ?」となる未来が見えている
    • モジュールごとに役割をはっきり分けておくと、「エンコード周りはここ」「行フィルターはここ」と 頭の切り替えがしやすい
  • ブログの“設計メモ”としても読みやすくするため
    • 「このツール便利でした」だけで終わらせるのではなく、 「こう分割しておくと後からバージョンアップしやすいよ」という設計の考え方も残しておきたい
    • 同じように EC まわりのツールを作りたい人がいたときの、ひとつの参考例になればいいな、というおまけの狙いもあります

自分用ツールだからこそ、「今の自分」と「未来の自分」と「別UI版」に優しくしておく設計、という感じです。
その意味で、このツール自体が「モジュール設計のお試し台」になっています。


内部構成(モジュール設計)

コード全文はここでは省略して、どう分割しているかだけメモしておきます。
ディレクトリ構成はざっくりこんな感じです。

project_root/
├─ run_row_filter_app.py        ← 起動用スクリプト(EXE化のエントリポイント)
└─ row_filter_tool/
   ├─ __init__.py
   ├─ gui_row_filter_app.py     ← CustomTkinter の UI & イベント
   ├─ encoding_utils.py         ← 文字コード判定(chardet + フォールバック)
   ├─ data_io.py                ← DataFrame の読み込み・保存
   └─ row_filter_logic.py       ← 行グループ化とフィルター処理

encoding_utils.py(文字コード判定)

役割:

  • ファイル先頭の一部だけをバイナリで読み込む
  • chardet があればそれで推定し、ある程度の信頼度があれば採用
  • そうでなければ、UTF-8 / UTF-8-SIG / CP932 / EUC-JP の順に decode を試して通ったものを採用
  • どれもダメなら例外を投げる

これにより、「毎回エンコーディングを意識して開く」手間をなくすのが狙いです。

data_io.py(ファイル読み込み・保存)

役割:

  • 拡張子(.csv / .tsv / .txt / .xls / .xlsx / .xlsm)から「CSV系」か「Excel系」かを判定
  • CSV系の場合は encoding_utils で文字コードを推定してから pandas.read_csv を実行
  • Excel系の場合は pandas.read_excel を使って読み込み
  • 保存時は、元ファイルと同じ形式で to_csv / to_excel を呼ぶ

「ファイルパス ↔ DataFrame ↔ 保存パス」の責務をこのモジュールに寄せて、
GUI 側は極力「DataFrame という箱」とだけやり取りするようにしています。

row_filter_logic.py(行グループ化とフィルター適用)

役割:

  • 指定した列を見て、値ごとに行インデックスをまとめる
  • 「値」と「対応する行インデックスのリスト」をセットにしたオブジェクト(例:ValueGroup)の一覧を返す
  • 選択されたグループのインデックスを集約して、「削除」「残す」のどちらかのモードで DataFrame をフィルタリングする

ここは GUI に一切依存させず、純粋な関数群として作ってあります。
将来 FastAPI 版(Webフォームから列名と値を送り込むような形)を作るときも、
このモジュールをそのまま使い回せるようにするための分割です。

gui_row_filter_app.py(画面とイベント)

役割:

  • CustomTkinter を使ったウィンドウ・フレーム・ボタン・コンボボックスの定義
  • 列選択コンボボックスの変更イベントで、値リストを再生成
  • 3列の Listbox に値を割り振り(1列目:1,4,7… 2列目:2,5,8… という感じ)
  • クリック時に ON/OFF トグルできるようにするイベントハンドラ
  • 「実行して保存」ボタンから row_filter_logicdata_io を呼び出す

UI 部分はここに集約しているので、
「見た目を少し変えたい」「列数を3列から4列にしたい」といった調整も、このファイルだけ見れば済みます。

run_row_filter_app.py(ランチャースクリプト)

役割:

  • Python を触らない人向けに、起動用の入口を1つにまとめる
  • このファイルを PyInstaller で EXE 化することで、単体EXEを作る
  • sys.dont_write_bytecode = True を設定して、__pycache__ を作らないようにしている

EXE化と配布イメージ

今回は、インストール不要で動く「EXEひとつだけ」の形にしたかったので、
PyInstaller を使ってワンファイル化しています。

コマンドはこんなイメージです(参考程度のメモ):

pyinstaller --noconsole --onefile --name RowFilterTool run_row_filter_app.py
  • --noconsole : コンソール(黒い画面)を出さない
  • --onefile : 必要なモジュールを1つのEXEに固める
  • --name : 出力されるEXEファイル名

これで dist/RowFilterTool.exe ができるので、あとは

  • ブログからその EXE をダウンロードしてもらう
  • Windows でダブルクリックして起動

という使い方ができます。
Python をインストールしていない人(奥さん含む)でも、そのまま「行フィルターツール」として使える想定です。


なぜコードではなく「設計」を残すか

正直、AI 時代になると「コードそのもの」は、
かなりの部分を AI に任せることができるようになってきました。

実際、自分でも

  • 具体的な処理は AI に手伝ってもらう
  • 自分は「どう分割するか」「どこまで汎用にするか」「どこをモール依存にするか」を考える

という使い方をすることが増えています。

なので、ブログではあえてソースコード全文は載せず

  • どういう課題を解決したかったのか
  • どういうコンセプトで設計したのか
  • どこをモジュールとして分けたのか

といった設計レベルのメモを残しておくことにしました。

自分自身にとっても、

  • 後で FastAPI 版を作りたくなったとき
  • v2 でキーワード絞り込みを追加したくなったとき
  • 別のECモールのCSV用ツールを増やしたくなったとき

「何がどこまでできていて、どこから先を足すべきか」を思い出すためのログとしても役立つはずです。


これからの拡張アイデア

今回の v1 で一旦満足してはいるものの、「そのうちやりたいな」というネタもいくつかあります。

  • モール別プリセット
    • カラーミー / Yahoo / 楽天 など、モールごとに「よく使う列」を事前にセット
    • ブランド列やカテゴリ列をワンクリックで選べるようにする
  • キーワード絞り込み
    • 商品名や説明文に含まれる文字列で絞り込む
    • 「◯◯を含む/含まない」でフィルターできるようにする
  • FastAPI版Webアプリ
    • ブラウザからCSVをアップロードして、同じロジックでフィルターする
    • 結果をそのままダウンロード、みたいな簡易Webツール化

これは、チョー適当につくったツールです。
(※のちのちバージョンアップ予定)

**個人で作成した Windows 用の実行ファイル(RowFilterTool_v1.0.exe)** として配布しています。
そのため、環境によっては 初回起動時のみ
・Norton
・Windows Defender
・その他ウイルス対策ソフト
による 自動チェック が行われる場合があります。

私の環境(Norton)では、次のような挙動でした。

・EXE をダブルクリック
・ウイルスチェックが自動的に開始
・チェック中に、一度だけエラーダイアログが表示される
・チェック完了後、再度起動すると正常に起動

初回起動時にエラーが表示された場合でも、
少し待ってからもう一度起動してみてください。

「エクセルでいちいちフィルターかけるの飽きたな…」という方は、
自分用のこういう小さなツールを一つ持っておくと、
地味に作業ストレスが減るのでおすすめです。

※ 本ツールは個人制作の無償ツールです。  利用は自己責任でお願いします。  必ず元データのバックアップを取ってからご利用ください。

そしてサックは今日も元気にロングリードを引きちぎりそうなので、
次のパラコード版は、もう少し金具を強いものにしようと思います…。

投稿日:2025/12/15

お気軽にコメントください。