雑記帳

CGI を介して実行された Python スクリプトの吐き出すページが文字化けを起こす件

このページでは「Python を CGI 経由で実行させる」という形でページの動的生成を行う際に生じた文字化けに関する問題の対処方法を紹介。
(「CGI / Python」はあまり推奨されておらず、時代と逆行する方法なのかもしれないけど、物好きがいるかもしれないので一応...)
経緯
「Windows マシンに Apache HTTP Server をインストールする形で自前のサーバーを立て、そこで CGI の動作チェック (CGI 経由での Python スクリプト実行によるページの動的生成が正しくできるのかの確認) を行う」みたいなことをやろうと試みたところ、日本語の文字化け問題に直面。
具体的には、出力される日本語の文字コードが「Shift-JIS」となってしまうというもの。
そのため、ヘッダに「Content-type: text/html;charset=utf-8」などと書いてしまうと、Shift-JIS でエンコードされたコードが無理やり UTF-8 で読み込まれるため、日本語が文字化けしてしまう。
レンタルサーバー上ではこの問題に直面することはなかったので、普通にコンピュータのシステムロケールの設定辺りを弄ればどうにかなる問題ではあると思うのだけど、どうせならプログラム側で対処したいと考え、ちょっと模索してみたらちゃんと解決方法があったので情報共有。
まず Python とは直接関係のない言語ではあるが、僕の大好きな Haskell でも日本語を扱う (一般に Unicode 対応の) プログラムを作るときは
{-# LANGUAGE OverloadedStrings #-}
import GHC.IO.Encoding
import qualified Data.Text    as T
import qualified Data.Text.IO as T

main = do
  setLocaleEncoding utf8
というように、エンコードの設定を UTF-8 にしてあげる IO アクションから始めるのが常套だった。
なのでその類推から、もしかすると Python でも似たようなことをして標準出力に吐き出すときに採用する文字コードを UTF-8 にしてあげるみたいなことができるのではと思って、その線を攻めてみたら
import sys

sys.stdout.reconfigure(encoding='utf-8')
でまさにそれができることがわかったという流れ。
(「setLocaleEncoding」)
具体例
サンプルコードとして、超簡易的な HTML を生成する CGI / Python コードを載せておく。
#!/usr/local/bin/python3

import sys

sys.stdout.reconfigure(encoding='utf-8')

print("Content-type: text/html;charset=utf-8\n\n<!DOCTYPE html><html lang=\"ja\"><body>日本語表示テスト (UTF-8)</body></html>")
注意点としては
  • その CGI ファイルの文字コードも「UTF-8」にする
  • 「#!/usr/local/bin/python3」は HTTP サーバーを動かしているマシンにインストールされている Python の実行ファイルのパスなので、適宜変更する必要あり。例えばパスが「C:\Python312\python.exe」の場合は「#!/Python312/python」になる
  • 言うまでもないかもしれないけど、その CGI ファイルが実行できるようにパーミッションを与えておかないとエラーを起こす