Gif秒数カウンターをWebアプリに変換!
前回は、Pythonで作った簡単なハローワールドやジャンケンなどをブラウザで動かす練習をしました。
今回は、前に作ったGIF秒数カウンターをWebアプリにして公開してみようと思います。
今日のハイライト
GIF秒数カウンターのWEBアプリ版です。
ファイルアップロード機能を作る
新しいフォルダ
WEBアプリ化のための新しいフォルダ構成を作ります。
gif_web_app/
├── app.py # Flaskアプリケーション本体
├── templates/
│ └── index.html # ユーザーが見るHTMLページ
└── uploads/ # アップロードされたGIFが保存されるフォルダFlaskアプリケーション(app.py)
まず、メインのPythonファイルを作成します。このコードは、ファイルのアップロードを受付け、指定したuploadフォルダに保存する機能を持っています。gif_web_app/app.pyという名前で以下のファイルを作成します。
app.py
import os
from flask import Flask, request, render_template, flash, redirect, url_for
from werkzeug.utils import secure_filename
# --- 設定 ---
# アップロードされたファイルを保存するフォルダ
UPLOAD_FOLDER = 'uploads'
# アップロードを許可するファイルの拡張子
ALLOWED_EXTENSIONS = {'gif'}
# --- Flaskアプリケーションの初期化 ---
app = Flask(__name__)
# UPLOAD_FOLDERをFlaskの設定に追加
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# flashメッセージ(ユーザーへの通知)機能に必要な秘密鍵
app.config['SECRET_KEY'] = 'a_very_secret_key_for_flash_messages'
# アップロードされるファイルの最大サイズ(例: 16MB)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
# --- ヘルパー関数 ---
def allowed_file(filename):
"""アップロードされたファイルが許可された拡張子かチェックする"""
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
# --- ルーティング ---
@app.route('/', methods=['GET', 'POST'])
def upload_file():
# POSTリクエスト(ファイルがアップロードされた)の場合
if request.method == 'POST':
# リクエストにファイルが含まれているかチェック
if 'file' not in request.files:
flash('ファイルがリクエストに含まれていません')
return redirect(request.url)
file = request.files['file']
# ユーザーがファイルを選択しなかった場合(ファイル名が空)
if file.filename == '':
flash('ファイルが選択されていません')
return redirect(request.url)
# ファイルが選択され、かつ許可された拡張子の場合
if file and allowed_file(file.filename):
# 安全なファイル名に変換(危険な文字を削除)
filename = secure_filename(file.filename)
# ファイルを UPLOAD_FOLDER に保存
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
# 成功メッセージを表示
flash(f'ファイル "{filename}" のアップロードに成功しました!')
# 次のフェーズでは、ここでGIFの解析処理を呼び出すことになります。
return redirect(url_for('upload_file'))
# GETリクエスト(単にページを訪れた)の場合
return render_template('index.html')
if __name__ == '__main__':
# 'uploads' フォルダがなければ作成する
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
app.run(debug=True) # debug=True は開発中のみ使用しますHTML(index.html)
次に、ブラウザで見る画面を templates フォルダ内に作成します。
index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>GIFアップローダー</title>
<style>
body { font-family: sans-serif; margin: 2em; background-color: #f4f4f9; }
.container { max-width: 500px; margin: auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
h1 { color: #333; }
.flash { padding: 1em; margin-bottom: 1em; border-radius: 4px; }
.flash.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.flash.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
input[type=file] { margin-bottom: 1em; }
input[type=submit] { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; }
input[type=submit]:hover { background-color: #0056b3; }
</style>
</head>
<body>
<div class="container">
<h1>GIF情報カウンター (フェーズ1)</h1>
<p>解析したいGIFファイルをアップロードしてください。</p>
<!-- Flaskからのメッセージ(flash)を表示するエリア -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<!-- 成功メッセージとエラーメッセージでスタイルを分ける(今は成功のみ) -->
<div class="flash success">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<!-- ファイルアップロード用のフォーム -->
<form method="post" enctype="multipart/form-data">
<input type="file" name="file" accept=".gif">
<input type="submit" value="アップロードして解析">
</form>
</div>
</body>
</html>実行
仮想環境を設定
ターミナルで、仮想環境を設定します。
仮想環境を作ると、独自のPythonやツールのバージョンで実行でき、他のアプリの影響を受けないため、安定して変換できる環境になります。
.\.venv\Scripts\Activate.ps1ターミナルの先頭に (.venv) がつけば仮想環境になっています。
ライブラリのインストール
ターミナルでgif_web_appフォルダに移動し、Flaskをインストールします。
pip install Flaskアプリケーションの実行
ターミナルでapp.pyを実行します。
python app.pyブラウザでアクセス
Running on http://○○○○とでたら、そのIPアドレスをブラウザに入力します。この時、赤字でWarningが出ますが、それは「これはローカルだけで実行可能でサーバーではダメよ」という内容なので、むしろ、成功です。
ブラウザにIPを入れると、こんな感じの表示が出てきます。

「ファイルを選択」して、「アップロードして解析」をクリックして、uploadにファイルが入っていれば成功です。

GIF解析機能の実装と結果表示
GIFtimecount.pyを組み込む
GIFtimecount.pyの機能を、app.pyに組み込んで、解析結果をindex.htmlで見られるように修正します。
※ここからは、ファイルが大きくなりすぎるのでコードは割愛。公開版を見てください。
ターミナルの仮想環境で実行します。
python app.pyIPアドレスをブラウザで実行します。
「ファイルを選択」してGIFアニメーションを選択し、「アップロードを解析」を押すと、再生時間、フレーム数、FPSが出ました。

デザインを修正しました。

デプロイの準備
本番用サーバー gunicorn のインストール
Flaskに付属の開発用サーバーから、本番環境に対応したサーバーをターミナルの仮想環境にインストールします。
pip install gunicornrequirements.txt の作成
requirements.txt は、このプロジェクトが必要とするPythonライブラリの一覧が書かれたファイルです。Renderは、このファイルを見て必要なライブラリを自動でインストールしてくれます。
pip freeze > requirements.txtこれを実行すると、以下のような requirements.txt ができます。
blinker==...
click==...
colorama==...
Flask==...
gunicorn==...
....gitignoreファイルの作成
Gitに不要なファイルが含まれないように、.gitignoreファイルを新規に作成します。
# Python
__pycache__/
*.pyc
# Virtual Environment
.venv/
venv/GitHubに公開用の新しいリポジトリを作る
GitHubに公開用のリポジトリを作って、作ったプログラムを入れました。

Render.comで公開
Render.comのアカウントを作る
Render.comは、フリープランのあるホスティングサービスです。
ここで公開するために、ホームページから新規アカウントを作ります。
Get Started for Freeをクリック

今回はGitHubでアカウントを作ります。
ここから、ブラウザの機能で日本語化して説明します。

GitHubと接続して、そのままログインします。

Render.comで新しいWebサービスを作成する
上の「+新しい」(英語はNew+)からウェブサービスを選びます。

一番下のGitHubを選択します。

GitHubで追加するリポジトリを指定して一番したの Install をクリック。

内容を確認
Languageは「Python3」、Build Command は「pip install -r requirements.txt」、Start Command は「gunicorn app:app 」になっていることを確認します。
確認ができたら、ページの一番最後にある「Deploy Web Service」をクリックします。

修正は、Githubにプッシュした瞬間から自動的に更新されて便利です。
公開ファイル

なんか知らんが嬉しい!
簡単なプログラムですが、苦労した分、メッチャ嬉しいです。
誰かの参考になれば幸いです。
