1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GoogleColaboratoryを使ってみよう

Last updated at Posted at 2025-10-28

💀 はじめに:退職者が作ったツールが消えた

ある日、社内で「例のツール、もう動かないんだけど?」と現場から問い合わせが来ました。
話を聞くと、別部署のスーパーハカーが以前作った、「CSV整理ツール」があったらしい。
(そういえば作ってもらった気がする)

だがしかしその本人はすでに退職済み。
引き継ぎ項目にも残っておらず、アカウント削除とともにツールが消滅。
GWSのアカウント消す時に引き継ぐ項目に入ってないから、個別にやっとかなきゃいけなかったらしい!盲点すぎるだろ!

Colabで作ってたらしいことと、残されたマニュアルから、ツールを復元してみようの回です

当方、パイソン チョトワカル プログラミング チョトワカル 程度の情シス要員です
コード自体はちゃっぴー(ChatGPT)に命令して作ってもらいました


💡 そもそもGoogle Colabってなに?

「Google Colab(コラボ)」は、Googleが提供している ブラウザ上でPythonを実行できる無料環境。(らしい)(知らんかった)
正式名称:GoogleColaboratory

  • インストール不要(ブラウザだけで動く)
  • Googleアカウントさえあれば無料で使える
  • GPUなどのリソースも利用可能
  • Googleドライブと連携できる

つまり、「ちょっとPythonで処理したい」をすぐに試せる環境です。
特に社内PCにPythonを入れられない環境で使えたりする。
でもそんなにPython入れるのって手間ではなくない?
特に現場の人にWebアプリ見たいな感じで簡単に使えるツールを提供できるのが便利だな~って実感しました


⚠️ 注意:Google Workspaceでは使えないことも

会社や学校などの Google Workspace アカウント(@会社名ドメイン) では、
管理者がColabを許可していないと利用できません。

このサービスは管理者によって無効にされています。

と出る場合は、 管理者に「Colaboratoryの使用許可」を依頼してください。


🤔 GAS(Google Apps Script)じゃだめなの?

てかGASの方が手軽だしGASじゃだめなの?
駄目らしい

項目 GAS Colab
ファイル操作 DriveApp経由で都度ファイル取得が必要 FileUploadウィジェットで即アップロード可
日本語文字コード(Shift_JISなど) やや扱いにくい pandasでエンコーディング指定が容易
UI(ボタン・進行表示) HTMLServiceが必要 ipywidgetsで即作成可
実行速度 やや遅め(制限あり) ローカル実行に近い速度
実行環境 Googleサーバー内、Apps Script制限下 Pythonそのもの、柔軟

つまり、
「現場向けに、ドラッグ&ドロップで完結するCSVクリーナーを作りたい
という要件では、Colabが圧倒的に速かったんです。


🧰 作ったもの:Shift_JIS非対応文字クリーナー

以下が復元したツールの実体。
CSVをアップロードすると、

  • A〜K列の重複削除
  • Shift_JISで保存できない文字の検出と除去
  • 処理済みCSVを自動ダウンロード

を自動で行います。
ブラウザ上でGUI操作できるので、Pythonを知らなくても扱えます。

何故これを作りたかったといえば、皆さんご存知の通りCSVって開いて保存するときにコツがいるじゃん
特に小売りの人はあるあるだと思うんですけど、CSV内のJANコードが変になっちゃったりしたいね
なので、現場の人にはCSVを開かずに、作業を簡潔させるツールを作りたかったってわけです


💻 コード全文

Colabの基本的な使い方はここでは省略します
各自調べて使ってみてください
私もなんとなくでやりました

それで紆余曲折あーでもないこーでもない格闘して
こちらが出来上がったものです

Colabでそのまま貼り付けて動かせます。
初回は「初回のみ押す」ボタンでライブラリを自動インストール。

# @title Shift_JIS非対応文字クリーナー(Colab用)
import pandas as pd
import ipywidgets as widgets
from IPython.display import display, clear_output
import io, sys, subprocess

# --- chardetインストールボタン ---
install_log = widgets.Output()
def install_chardet(b):
    install_log.clear_output()
    with install_log:
        print("chardetをインストールしています...")
        try:
            subprocess.check_call([sys.executable, "-m", "pip", "install", "chardet"])
            print("chardetのインストールが完了しました!")
        except Exception as e:
            print("インストールに失敗しました:", e)

install_button = widgets.Button(description='初回のみ押す', button_style='warning', icon='download')
install_button.on_click(install_chardet)

# --- Shift_JIS判定関数 ---
def can_encode_shift_jis(char):
    try:
        char.encode('shift_jis')
        return True
    except UnicodeEncodeError:
        return False

# --- UI構成 ---
upload_status = widgets.HTML(value='<span style="color:gray;">アップロード待機中</span>')
uploader = widgets.FileUpload(accept='.csv', multiple=False, description='ファイルを選択またはドロップ',
    layout=widgets.Layout(width='360px', height='80px', border='2px dashed #aaa'))
start_button = widgets.Button(description='削除開始', button_style='success', icon='check')
help_button = widgets.Button(description='スタートボタン', button_style='info', icon='info-circle')
download_link = widgets.HTML(value='ダウンロードリンクはここに表示')
result_log = widgets.Output()

def on_help_clicked(b):
    result_log.clear_output()
    with result_log:
        print("【使い方ガイド】")
        print("1. 『初回のみ押す』でchardetを導入。")
        print("2. CSVをアップロード。")
        print("3. 『削除開始』でShift_JIS非対応文字と重複を除去。")
        print("4. ダウンロードリンクから取得。")
help_button.on_click(on_help_clicked)

left_box = widgets.VBox([
    install_button, install_log, help_button,
    widgets.Label('【1】ファイルアップロード'),
    upload_status, uploader,
    widgets.Label('【2】下のボタンで削除開始'),
    start_button
], layout=widgets.Layout(width='400px'))

right_box = widgets.VBox([
    widgets.Label('【3】ダウンロード'),
    download_link,
    widgets.Label('【4】ログ'),
    result_log
], layout=widgets.Layout(width='540px'))

display(widgets.HBox([left_box, right_box]))

# --- 処理ロジック ---
def on_upload_change(change):
    if uploader.value:
        upload_status.value = '<span style="color: blue;">アップロード完了!</span>'
    else:
        upload_status.value = '<span style="color: gray;">アップロード待機中</span>'
uploader.observe(on_upload_change, names='value')

def on_start_clicked(b):
    result_log.clear_output()
    if not uploader.value:
        with result_log: print('⚠️ ファイルをアップロードしてください')
        return

    upload_status.value = '<span style="color: orange;">処理中...</span>'
    uploaded_file = list(uploader.value.values())[0]
    filename = uploaded_file['metadata']['name']
    raw_data = uploaded_file['content']

    try:
        text_data = raw_data.decode('shift_jis', errors='ignore')
        df = pd.read_csv(io.StringIO(text_data))
    except Exception as e:
        with result_log: print(f'読み込み失敗: {e}')
        upload_status.value = '<span style="color: red;">ファイル読み込み失敗</span>'
        return

    df = df.drop_duplicates(subset=df.columns[:11], keep='last')

    logs = []
    df_cleaned = df.copy()
    for i, row in df.iterrows():
        for col in df.columns:
            val = str(row[col])
            try:
                val.encode('shift_jis')
            except UnicodeEncodeError:
                cleaned = ''.join([c for c in val if can_encode_shift_jis(c)])
                invalid = ''.join([c for c in val if not can_encode_shift_jis(c)])
                df_cleaned.at[i, col] = cleaned
                logs.append((i+2, col, invalid))

    output_filename = f'processed_{filename.replace(".csv", "")}_sjis_clean.csv'
    try:
        df_cleaned.to_csv(output_filename, index=False, encoding='shift_jis')
        from google.colab import files
        files.download(output_filename)
        upload_status.value = '<span style="color: green;">完了!</span>'
    except Exception as e:
        with result_log: print(f"保存エラー: {e}")
        upload_status.value = '<span style="color: red;">保存エラー</span>'
        return

    with result_log:
        if logs:
            print("\n【Shift_JIS非対応文字 削除ログ】")
            for r, c, inv in logs:
                print(f"{r}・列「{c}」: 非対応文字「{inv}」を削除しました。")
        else:
            print("Shift_JIS非対応文字は検出されませんでした。")

start_button.on_click(on_start_clicked)

全然身になった感じは全くないんだけど、少し賢くなった気がする!
おわり

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?