PythonでCGI可能なローカルWebサーバー
[質問]
ローカルPCで、自分だけ使うGUIプログラムを作ります。 バックエンドはPythonによるローカルWEBサーバーと、そこで実行されるPython-CGIとします。 フロントエンドはHTML+JavaScriptです。localhostでの利用が前提です。
次の構成で、サンプルプログラムを作ってください。
(1) Pythonを利用した、CGIも実行可能なWebサーバー。
(2) 簡単なCGIで、ドキュメントルート外のファイルを読み書きするサンプル。
(3) CGIにアクセスするHTML+JavaScript。
[回答] Grok
以下は、ご要望通りの完全動作するサンプルプログラムです。
localhost(127.0.0.1)限定で、自分だけが使うGUIプログラムとして最適化しています。
ディレクトリ構成(これを作成してください)
project/ ← 任意のフォルダ名でOK
├── server.py ← Webサーバー起動スクリプト
├── www/
│ ├── index.html
│ └── script.js
├── cgi-bin/
│ └── file_handler.py ← CGI(ドキュメントルート外のファイルを読み書き)
└── data/ ← 自動作成されます(ノート保存用)
(1) Python Webサーバー(server.py)
import os
from functools import partial
from http.server import HTTPServer, CGIHTTPRequestHandler
def main():
# ドキュメントルートを www フォルダに固定
web_dir = os.path.join(os.path.dirname(__file__), 'www')
# CGI対応ハンドラ(directory指定)
Handler = partial(CGIHTTPRequestHandler, directory=web_dir)
# localhost:8000 で起動
server_address = ('127.0.0.1', 8000)
httpd = HTTPServer(server_address, Handler)
print("=== ローカルGUIサーバー起動 ===")
print(f"http://{server_address[0]}:{server_address[1]}")
print("ブラウザで上記URLを開いてください。")
print("終了は Ctrl+C")
httpd.serve_forever()
if __name__ == "__main__":
main()
(2) CGIサンプル(cgi-bin/file_handler.py)
ドキュメントルート外(../data/notes.txt)を自由に読み書きします。
#!/usr/bin/env python3
import cgi
import cgitb
import os
import json
cgitb.enable() # エラー時にブラウザに詳細表示(開発用)
# =============================================
# ドキュメントルート外のファイルパス
# =============================================
script_dir = os.path.dirname(__file__) # cgi-bin/
project_dir = os.path.dirname(script_dir) # project/
data_dir = os.path.join(project_dir, 'data')
os.makedirs(data_dir, exist_ok=True)
DATA_FILE = os.path.join(data_dir, 'notes.txt')
# =============================================
# メイン処理
# =============================================
form = cgi.FieldStorage()
action = form.getfirst('action')
if action == 'load':
content = ''
if os.path.exists(DATA_FILE):
with open(DATA_FILE, 'r', encoding='utf-8') as f:
content = f.read()
print('Content-Type: application/json')
print()
print(json.dumps({'status': 'ok', 'content': content}))
elif action == 'save':
content = form.getfirst('content', '')
with open(DATA_FILE, 'w', encoding='utf-8') as f:
f.write(content)
print('Content-Type: application/json')
print()
print(json.dumps({'status': 'ok'}))
else:
print('Content-Type: text/plain')
print()
print('Unknown action')
Windowsの場合
shebang行(1行目)はそのままでも動きますが、動かない場合は
#!C:\Python312\python.exe(ご自身のPythonパス)に変更してください。
(3) フロントエンド(HTML + JavaScript)
www/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ローカルGUIサンプル</title>
<script src="script.js" defer></script>
<style>
body { font-family: sans-serif; margin: 20px; }
textarea { width: 100%; max-width: 800px; font-size: 16px; }
button { padding: 10px 20px; font-size: 16px; margin-right: 10px; }
#status { font-weight: bold; }
</style>
</head>
<body>
<h1>ローカルGUIサンプル(Python CGI + HTML+JS)</h1>
<p>このテキストエリアの内容は <code>../data/notes.txt</code> に保存されます。</p>
<textarea id="note" rows="20" placeholder="ここに自由に書いてください..."></textarea>
<br><br>
<button onclick="loadNote()">📂 読み込み</button>
<button onclick="saveNote()">💾 保存</button>
<span id="status"></span>
</body>
</html>
www/script.js
async function loadNote() {
try {
const res = await fetch('/cgi-bin/file_handler.py?action=load', { method: 'GET' });
if (!res.ok) throw new Error('読み込み失敗');
const data = await res.json();
document.getElementById('note').value = data.content || '';
showStatus('✅ 読み込み完了', 'green');
} catch (e) {
showStatus('❌ 読み込みエラー: ' + e.message, 'red');
}
}
async function saveNote() {
const content = document.getElementById('note').value;
try {
const res = await fetch('/cgi-bin/file_handler.py', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ action: 'save', content: content })
});
if (!res.ok) throw new Error('保存失敗');
await res.json();
showStatus('✅ 保存完了', 'green');
} catch (e) {
showStatus('❌ 保存エラー: ' + e.message, 'red');
}
}
function showStatus(msg, color) {
const status = document.getElementById('status');
status.textContent = msg;
status.style.color = color;
setTimeout(() => status.textContent = '', 3000);
}
// ページを開いたときに自動で読み込み
window.onload = loadNote;
実行手順
- 上記のフォルダ・ファイルを作成(コピペでOK)
- ターミナル / コマンドプロンプトで
projectフォルダに移動 - 実行:
- ブラウザで http://127.0.0.1:8000/ を開く
→ テキストを入力 → 「保存」→ ブラウザを閉じても、次に開いたときに「読み込み」で復元されます!
これで完全にローカル完結のGUIプログラムが完成です。
必要に応じてボタンや機能を増やしたり、他のCGIを追加したりしてください。
質問があればいつでもどうぞ!
[管理者注] 修正版
Python 3.13 から cgi モジュールが使えなくなったので、 サードパーティ製の legacy-cgi をインストールすること。
あとディレクトリ構成は、次のようにwwwの中にcgi-binを入れないとだめだった。
project/
├── server.py
├── www/
│ ├── cgi-bin/
│ │ └── file_handler.py
│ ├── index.html
│ └── script.js
└── data/
これにともない、file_handler.py の次の1行を修正。
# =============================================
# ドキュメントルート外のファイルパス
# =============================================
script_dir = os.path.dirname(__file__) # cgi-bin/
project_dir = os.path.dirname(os.path.dirname(script_dir)) # ★ここを修正
data_dir = os.path.join(project_dir, 'data')
os.makedirs(data_dir, exist_ok=True)
なにか別のバグを見つけたらここに追加します。