はじめに
はじめまして、@umd55 です。
15年くらいメイクアップ化粧料の研究開発・処方設計をしていましたが、縁あって本年より社内ツール開発をしています。
初めてのプログラミング言語は Python で、爆速で開発したかったので Streamlit で開発することが多くなりました。
「Streamlit でいい感じのプロトタイプができた!チームメンバーに使ってもらいたい。」
次第にそう思うようになりました。しかしながら、サーバー構築やデプロイはハードルが高く、プロトタイプは爆速でも、共有するのに失速してしまう。
「作る」より「配る」が難しい・・・これが意外な壁でした。
そこでこの記事では、embedded Python + bat ファイルを使って、Python 未インストールの PC でも動く Streamlit アプリを配布する方法を紹介します。
共有ファイルサーバー上の CSV を読み込んで表示する、簡易検索アプリを例に解説します。
この方法のメリット
- サーバー不要: 今すぐ配布できる
- Python 未インストールでも動く: 配布先の PC に Python がなくても OK
- bat ダブルクリックで起動: デスクトップアプリ風の体験
全体像
開発者がやること
- uv をインストール
- uv で Streamlit アプリを開発
- requirements.txt を作成
- embedded Python を準備し、ライブラリをインストール
- フォルダを整えて zip 化
- チームに配布
配布先ユーザーがやること
- zip を展開
- bat をダブルクリック
これだけです。
めちゃくちゃ手軽です。
最終的な配布物
MyApp/
├── bin/
│ ├── python/ # embedded Python(pip install 済み)
│ │ ├── python.exe
│ │ ├── python313._pth
│ │ ├── Lib/
│ │ ├── Scripts/
│ │ └── ...
│ └── main.py # Streamlit アプリ
└── MyApp.bat # 起動用
ユーザーから見ると フォルダ1つ + bat 1つ だけです。シンプルなのでユーザーも迷いません。
前提条件
- OS: Windows 10 / 11
- 開発者: uv をこれからインストール(Python 不要)
- 配布先: Python 未インストールでも OK
Part 1: 開発者向け手順
Step 1: uv のインストール
PowerShell を開いて以下を実行します。
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
インストール後、ターミナルを再起動して確認します。
uv --version
バージョンが表示されれば OK です。
💡 uv とは?
uv は Rust 製の高速な Python パッケージマネージャーです。pip より 10〜100 倍高速で、仮想環境の作成・管理も一括で行えます。Python 自体のインストールも uv が自動で行ってくれるため、開発マシンに Python がなくても大丈夫です。
Step 2: Streamlit アプリの作成
作業フォルダを作成し、uv でプロジェクトを初期化します。
mkdir streamlit-app
cd streamlit-app
uv init
uv init を実行すると、以下のファイルが自動生成されます。
streamlit-app/
├── .git/
├── .gitignore
├── .python-version
├── main.py # ← この中身を Streamlit アプリに書き換えます
├── pyproject.toml
└── README.md
main.py には Hello World のテンプレートが入っています。これを Streamlit アプリに書き換えていきます。
Streamlit を追加します。
uv add streamlit pandas
main.py を以下の内容に書き換えます。共有ファイルサーバーの CSV を読み込んで表示する簡易検索アプリの例です。ここでは犬種データを例に解説します。
import streamlit as st
import pandas as pd
from pathlib import Path
# ===========================================
# 設定(ここを環境に合わせて変更)
# ===========================================
# UNC パス例: \\\\server\\share\\data
DATA_DIR = Path(r"\\server\share\data")
CSV_FILE = DATA_DIR / "dogs.csv"
# ===========================================
# アプリ本体
# ===========================================
st.set_page_config(page_title="犬種図鑑", layout="wide")
st.title("犬種図鑑")
@st.cache_data
def load_data():
if not CSV_FILE.exists():
st.error(f"CSV ファイルが見つかりません: {CSV_FILE}")
return pd.DataFrame()
return pd.read_csv(CSV_FILE, encoding="utf-8")
df = load_data()
if df.empty:
st.warning("データがありません。CSV ファイルのパスを確認してください。")
st.stop()
# サイドバー:検索フィルター
st.sidebar.header("検索条件")
search_text = st.sidebar.text_input("犬種名で検索")
# グループフィルター
groups = ["すべて"] + sorted(df["group"].dropna().unique().tolist())
selected_group = st.sidebar.selectbox("グループ", groups)
# サイズフィルター
sizes = ["すべて"] + df["size"].dropna().unique().tolist()
selected_size = st.sidebar.selectbox("サイズ", sizes)
# フィルタリング
filtered_df = df.copy()
if search_text:
filtered_df = filtered_df[
filtered_df["name"].str.contains(search_text, case=False, na=False)
| filtered_df["name_en"].str.contains(search_text, case=False, na=False)
]
if selected_group != "すべて":
filtered_df = filtered_df[filtered_df["group"] == selected_group]
if selected_size != "すべて":
filtered_df = filtered_df[filtered_df["size"] == selected_size]
# 結果表示
st.subheader(f"検索結果: {len(filtered_df)} 件")
# 表示するカラムを選択
display_columns = ["name", "name_en", "group", "size", "origin", "weight_kg", "height_cm", "lifespan"]
display_df = filtered_df[display_columns].copy()
st.dataframe(
display_df,
column_config={
"name": st.column_config.TextColumn("犬種名", width="medium"),
"name_en": st.column_config.TextColumn("英語名", width="medium"),
"group": st.column_config.TextColumn("グループ", width="small"),
"size": st.column_config.TextColumn("サイズ", width="small"),
"origin": st.column_config.TextColumn("原産国", width="small"),
"weight_kg": st.column_config.NumberColumn("体重(kg)", width="small"),
"height_cm": st.column_config.NumberColumn("体高(cm)", width="small"),
"lifespan": st.column_config.NumberColumn("寿命(年)", width="small"),
},
hide_index=True,
width="stretch",
)
動作確認します。
uv run streamlit run main.py
ブラウザが開き、アプリが表示されれば OK です。Ctrl + C で停止します。
サンプル CSV(dogs.csv)
id,name,name_en,group,size,origin,weight_kg,height_cm,lifespan
1,柴犬,Shiba Inu,日本犬,中型,日本,9,38,13
2,秋田犬,Akita,日本犬,大型,日本,45,66,11
3,トイプードル,Toy Poodle,愛玩犬,小型,フランス,3,26,14
4,チワワ,Chihuahua,愛玩犬,小型,メキシコ,2,18,15
5,ゴールデンレトリバー,Golden Retriever,レトリバー,大型,イギリス,32,58,11
Step 3: requirements.txt の作成
embedded Python にインストールするためのライブラリ一覧を出力します。
uv export --format requirements-txt --no-hashes > requirements.txt
💡 --no-hashes オプションについて
uv export はデフォルトでハッシュ付きの requirements.txt を出力しますが、embedded Python の pip ではハッシュ検証がうまくいかないことがあります。
--no-hashesを付けることでシンプルな形式になります。
Step 4: 配布用フォルダの作成と embedded Python の準備
開発環境(streamlit-app/)と配布物は分離します。
開発環境には uv で作成した .venv/、pyproject.toml、uv.lock などがありますが、これらは配布物には不要なためです。
配布用フォルダを作成
streamlit-app/ の親ディレクトリに移動してから、MyApp フォルダを作成します。
cd ..
mkdir MyApp
mkdir MyApp/bin
embedded Python のダウンロード
Python 公式サイト から Windows embeddable package (64-bit) をダウンロードします。
この記事執筆時点の最新版は Python 3.13.10 です。
直接リンク: https://www.python.org/ftp/python/3.13.10/python-3.13.10-embed-amd64.zip
展開・配置
- ダウンロードした zip を展開
- 展開したフォルダを
pythonにリネーム -
MyApp/bin/の中にpythonフォルダを配置
MyApp/
└── bin/
└── python/ # ← ここに展開した中身を配置
├── python.exe
├── python313._pth
├── python313.zip
└── ...
pip を使えるようにする
embedded Python はそのままでは pip が使えません。以下の手順で有効化します。
1. python313._pth を編集
MyApp/bin/python/python313._pth をテキストエディタで開き、#import site のコメントを外します。
python313.zip
.
# Uncomment to run site.main() automatically
- #import site
+ import site
2. get-pip.py をダウンロードして実行
MyApp フォルダに移動してから実行します。
cd MyApp
# get-pip.py をダウンロード
Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py -OutFile get-pip.py
# embedded Python で実行
.\bin\python\python.exe get-pip.py
# 不要になったら削除
Remove-Item get-pip.py
💡 なぜこれらの設定が必要か?
._pthファイルについて:
embedded Python は「埋め込み用途」を想定しており、デフォルトではsite-packagesを読み込まない設定になっています。import siteを有効にすることで、pip でインストールしたパッケージが正しく読み込まれるようになります。._pthファイルは Python のパス設定ファイルで、ここに記載されたパスのみがsys.pathに追加されます。
get-pip.pyについて:
embedded Python には pip が同梱されていません。get-pip.py は Python 公式が提供する pip インストール用のブートストラップスクリプトです。このスクリプトを実行することで、pip 本体とその依存パッケージ(setuptools、wheel)がインストールされます。
Step 5: ライブラリのインストール
MyApp フォルダ内で、embedded Python の pip を使って、requirements.txt のライブラリをインストールします。
.\bin\python\python.exe -m pip install -r ..\streamlit-app\requirements.txt
インストールが完了したら確認します。
.\bin\python\python.exe -m pip list
streamlit、pandas などがインストールされていれば OK です。
Step 6: アプリの配置と bat ファイルの作成
main.py をコピー
開発環境から main.py を MyApp/bin/ にコピーします。
Copy-Item ..\streamlit-app\main.py bin\
bat ファイルを作成
MyApp フォルダ内に MyApp.bat を作成します。
@echo off
cd /d %~dp0
bin\python\python.exe -m streamlit run bin\main.py
pause
💡 bat ファイルの解説
bat ファイルとは?
bat(バッチ)ファイルは、Windows のコマンドを記述したテキストファイルです。拡張子を.batにすると、ダブルクリックで中に書かれたコマンドが順番に実行されます。プログラムの起動手順を自動化したいときによく使われます。今回は「Python を起動して Streamlit アプリを実行する」という手順を bat ファイルにまとめています。各行の意味:
@echo off:コマンドの表示を抑制cd /d %~dp0:は bat ファイルのあるディレクトリに移動(ドライブをまたいでも動作)pause:エラー時にウィンドウがすぐ閉じないように
動作確認
MyApp.bat をダブルクリックして、アプリが起動することを確認します。
フォルダ構成の最終形
MyApp/
├── bin/
│ ├── python/
│ │ ├── python.exe
│ │ ├── python313._pth
│ │ ├── Lib/
│ │ ├── Scripts/
│ │ └── ...
│ └── main.py
└── MyApp.bat
zip 化
親ディレクトリに戻ってから、フォルダごと zip に圧縮して配布します。
cd ..
Compress-Archive -Path MyApp -DestinationPath MyApp.zip
Part 2: 配布先ユーザー向け手順
使い方(これだけ!)
- 受け取った
MyApp.zipを展開 -
MyApp.batをダブルクリック - コマンドプロンプトが開き、しばらく待つとブラウザが自動で開く
- アプリが表示される
Python のインストールは不要です。
終了方法
コマンドプロンプトで Ctrl + C を押すか、ウィンドウを閉じます。
初回起動時のファイアウォール警告
初回起動時に「Windows セキュリティの重要な警告」ダイアログが表示されることがあります。
これは Streamlit が Web サーバーとして動作するため、Windows ファイアウォールがネットワークアクセスを許可するか確認しています。
| 選択 | 動作 |
|---|---|
| キャンセル | 自分の PC(localhost)からのみアクセス可能 |
| 許可 | 同じネットワーク内の他の PC からもアクセス可能 |
1人で使う場合は「キャンセル」で問題ありません。 localhost へのアクセスはファイアウォールに関係なく動作します。
これで配布パッケージの完成です!
bat ファイルをダブルクリックするだけで Streamlit アプリが起動する、超手軽な配布パッケージができました。
以降は、より便利に使うための Tips を紹介します。ご参考まで。
Tips
ショートカットでもっと便利に
bat ファイルのショートカットを作成すると、デスクトップやタスクバーに配置できて便利です。
-
MyApp.batを右クリック → 「ショートカットの作成」 - ショートカットをデスクトップなど好きな場所に移動
- 好みでアイコンも変更可能(右クリック → プロパティ → アイコンの変更)
よくあるエラーと対処
| エラー | 原因 | 対処 |
|---|---|---|
python が見つからない |
bat 内のパスが間違っている |
bin\python\python.exe のパスを確認 |
ModuleNotFoundError: No module named 'xxx' |
ライブラリ未インストール |
pip install を再実行 |
| ブラウザが開かない | ファイアウォール or ポートブロック | http://localhost:8501 を手動で開く |
| CSV の文字化け | エンコーディングの不一致 |
encoding='cp932' or 'utf-8' を指定 |
python313._pth の編集を忘れた |
pip は通るが import で失敗 |
import site のコメントを外す |
この方法の限界と次のステップ
この方法ではソースコードが見える状態で配布することになります。あくまで社内共有・プロトタイピング用途としてご利用ください。
この方法が向いているケース
- ✅ プロトタイプの共有
- ✅ 少人数(数名〜十数名)での利用
- ✅ 社内ネットワーク内での利用
この方法が向いていないケース
- ❌ 多人数での同時アクセス(数十人以上)
- ❌ 社外への配布
- ❌ 本番運用・長期運用
おわりに
この記事では、embedded Python + bat ファイル を使って、Streamlit アプリをサーバー不要で配布する方法を紹介しました。
開発者側は、uv で快適に開発しながら、配布用には embedded Python を使うことで環境構築の手間を省けます。ユーザー側は、zip を展開して bat をダブルクリックするだけ。Python のインストールも不要で、すぐにアプリを使い始められます。
プロトタイプ共有に最適な方法ですが、本格運用には別の方法を検討してくださいね。
「サーバー立てるほどじゃないけど、チームメンバーに使ってもらいたい!」そんなときに、ぜひ試してみてください!
ちなみに、Streamlit を手軽に共有する方法はこれだけではありません。明日のアドベントカレンダーでは、また違ったアプローチが紹介される予定です。そちらもぜひお楽しみに!
参考リンク
