こん○○は、よふかしわーくすのよふかしさんです
よふかしさんはちょっとしたツールを作るのに一番使うのはPythonなんですが
これをベースにWebアプリとか作れないかな?と思ってました
先日、レンタルサーバー上にPythonとmatplotlibを構築するところまでやりました
https://www.blog.yofukashi-works.com/?p=2049
今回は実際にさくらインターネットのレンタルサーバー上でPythonコードをCGIで動かして
WordPressサイト上にWebアプリとして公開する手順を解説したいと思います
今回も例にもれず色々とハマりました…
Python CGIとは?なぜWordPressと組み合わせるのか
CGI(Common Gateway Interface)とは、Webサーバーが外部プログラム(今回の場合はPython)を呼び出して、その出力をHTTPレスポンスとして返す仕組みです
さくらインターネットでは、.pyファイルをCGIとして実行可能なので、ちょっとした処理系Webアプリの構築ができます
というわけで、PythonをCGIで動作させる特徴を簡単にまとめてみました
- Pythonロジック+HTMLで簡単に構築できる
- Pythonライブラリを活用することで、JavaScriptだけでは難しい処理も実現可能
- 動作は高速ではないが、小規模、低トラフィックであれば問題ないレベル
- WordPressにiframeで簡単に埋め込み可能
- ロジックをユーザーには非公開でバックエンドで実行できる
上位互換な別方策もあるのですが、今回は初トライということもあって、レガシーなCGIベースでやってみました
パフォーマンスやメンテナンス性についてはまずは実際に作ってみてから、今後の改善を検討することにします
Python CGIサンプルコード(初版)
まずは、Pythonのサンプルコードを準備してみます
最大角度を入力すると、0~入力角度までの正弦波をグラフ化するツールです
これを基に解説をしていきます
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cgi
import matplotlib.pyplot as plt
import numpy as np
import base64
import io
print("Content-Type: text/html; charset=utf-8\n")
form = cgi.FieldStorage()
max_x_str = form.getfirst("max_x", "360") # デフォルト360
try:
max_x = int(max_x_str)
except ValueError:
max_x = 360
# グラフを描画
x = np.linspace(0, max_x, 500)
y = np.sin(np.radians(x))
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title("y = sin(x)")
ax.set_xlabel("x(度)")
ax.set_ylabel("y")
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
img_base64 = base64.b64encode(buf.read()).decode("utf-8")
buf.close()
# HTML出力
print(f"""
<!DOCTYPE html>
<html>
<head><meta charset="utf-8">
<title>CGI Graph Test</title>
<style>
body {{
font-family: Arial, sans-serif;
background-color: #f7f7f7;
text-align: center;
}}
form {{
margin-top: 20px;
}}
</style>
</head>
<body>
<h2>sin(x) グラフ生成</h2>
<form method="get">
最大 x 値(度): <input type="text" name="max_x" value="{max_x}">
<input type="submit" value="グラフ生成">
</form>
<hr>
<img src="data:image/png;base64,{img_base64}" alt="グラフ画像">
</body>
</html>
""")
Shebang
最初の一行目、!/usr/bin/env python3、はShebang(シバン/シェバン)と呼ばれる、
このファイルはどのプログラムから実行させるかをOSに伝える役割を持っています
今回はさくらインターネットのデフォルトではなく、自身で構築したPython3.9.18を使うため、そのパスを指定しておきます
pythonのパスがわからなくなってしまった場合は、下記コマンドで探すと便利です
% find ~ -name "python3*" | grep "/bin/"
/home/username/venv-py39/bin/python3.9
/home/username/venv-py39/bin/python3
/home/username/local/python3.9.18/bin/python3.9
/home/username/local/python3.9.18/bin/python3.9-config
/home/username/local/python3.9.18/bin/python3
/home/username/local/python3.9.18/bin/python3-config
この結果を受けて、前回作成したvenv環境である、
/home/username/venv-py39/bin/python3
を使うことにしますので、先頭行は下記の通り書き換えます
#!/home/username/venv-py39/bin/python3
HTML出力
HTMLはprint(f”””…”””)の中に書くことで出力されます
f”””…”””はf-string構文といって、{変数名}としたものを変数として扱ってくれる機能です
fをつけないと、{変数名}はただの文字列としてprintされてしまうので必須です
ただし、<style>タグの様にbody{…}という記述を構文として使用したい場合、逆に変数だと誤解してしまうので、
それを避けるためにbody{{…}}という様に、中括弧を二重に記述することでリテラルとして出力させる、という点に注意です
改行コードとエンコード
さくらインターネットのサーバーで実行させるための設定です
- 改行コードは LF(Unix形式)にすること
- エンコードはUTF-8(BOMなし)でファイル保存すること
Windows環境で開発していると標準設定では、改行コードがCRLF、エンコードがShift-JISになるエディタもあるので要注意です
Pythonコードの設置と実行準備
サーバー上の任意の場所に設置します
今回は、/home/username/www/blog/WebApp/cgi_test.py、という感じに置いてみます
パーミッションは705にすることで実行可能となります
chmod 705 cgi_test.py
CGIを正しく実行するには、.htaccessに以下を追加します
Options +ExecCGI
AddHandler cgi-script .py
.pyファイルをCGIスクリプトとして実行するための基本設定です
これがないと、Pythonファイルの中身がそのまま表示されてしまい、Webアプリとして動作しません
実行してみる
実行結果です
下記の様になりました

ちゃんとWebアプリとして実行できています!
…が、matplotlibのグラフ内の日本語が文字化けしてしまいます
日本語の文字化け対策:日本語フォントのインストール
そもそも、なぜ文字化けするのか?、ですが、
Windowsなどでは日本語フォントが標準でインストールされているので問題にならないのですが、
今回のレンタルサーバー上では日本語フォントが入っていなかった、というのが理由です
その場合は文字がわからないため、豆腐文字(□)として表示されてしまいます
という訳で、日本語フォントをインストールしていきます
まずは、下記よりDownloadします

今回は、IPAexゴシック(Ver.004.01)
ipaexg00401.zip(4.0MB)
を使用します
展開してできたipaexg.ttfを、適当なフォルダにUploadします
今回は、/home/username/www/blog/WebApp/font/ipaexg.ttf、という様に置きました
先のPythonコードに対して、下記の通り、追加・修正します
import matplotlib # 追加
from matplotlib import font_manager # 追加
font_path = "/home/username/www/blog/WebApp/font/ipaexg.ttf" # 追加
fp = font_manager.FontProperties(fname=font_path) # 追加
matplotlib.rcParams["font.family"] = fp.get_name() # 追加
ax.set_title("y = sin(x)", fontproperties=fp) # 修正
ax.set_xlabel("x(度)", fontproperties=fp) # 修正
ax.set_ylabel("y", fontproperties=fp) # 修正
そうすると、日本語の文字化けが解消されます

WordPressへの埋め込み
普通にそのままWebページとして公開してもいいのですが、今回はWordPressに埋め込んでみます
例えばWordPressの固定ページを開き、以下のようなiframeタグを挿入すると実現できます
<div style="max-width: 100%; overflow-x: hidden;">
<iframe id="gearCalcFrame"
src="https://www.blog.yofukashi-works.com/WebApp/cgi_test.py"
width="100%" height="800"
frameborder="0"></iframe>
</div>
一旦、簡単なサンプルとしてはこんな感じです
表示関連はHTML側のstyleとWordPress側の兼ね合いで調整していく必要も出てくると思います
終わりに
こんな感じでPythonで作ったWebアプリをWordPressに統合して公開することができました
Python CGIの強みは、軽量ながらも自由度の高いロジック実装ができること、
またWordPressと組み合わせることで、インタラクティブでユーザーに価値あるWebアプリを構築・公開することが可能になるかな、と思います
今回のサンプルを埋め込んでみたものは下記で確認できます
コメント