2025/10/23(木) [n年前の日記]
#1 [python] Pythonスクリプトをまだ修正中
ここ数日、ギャラリーページっぽいhtmlを生成するPythonスクリプトを書いてたけれど。一応それらしく動くようになってきたので、親父さん用PCに持っていって動作確認してみた。
いやはや、バグが出るわ出るわ…。親父さんはファイル管理が乱雑なので、お行儀が良い(?)自分の環境上では出てこなかった想定外の事態が次々に。
サブディレクトリやファイルを検索する際に、特に考えずに os.walk() を使ってしまって失敗した。サブディレクトリ内のサブディレクトリもリストアップしてしまって妙なページが出力されてしまう。os.walk() はディレクトリツリーを辿って全ファイルを検索する関数だから当たり前なのだけど…。os.listdir() を使って1階層だけ対象にするように変更した。
対象になる画像ファイルの拡張子はきっと ".jpg" だけだろうと決めつけて処理を書いていたけれど。親父さんの作ったサイトには ".JPG" もあって…。自分が画像ファイルを作成する時は必ず小文字の拡張子をつけているから、こんなトラップがあることに気づかなかった…。.lower() で小文字化して拡張子を比較することにした。
せっかくだからサムネイル画像を自動生成する処理を追加。画像処理ライブラリ Pillow の Image.resize() を使った。しかし、特定のフォルダを含めて処理させた時だけ、生成サムネイル画像数と、ページに列挙する画像ファイル数が違ってしまう…。何故。
原因が分かった。サムネイル画像が既にある場合、求めている画像サイズと同じなら再生成の必要無しと判断してスキップしているあたりが絡んでた。縦と横のどちらを基準にするかのチェックボックスを変えながら生成し直して動作確認してたけど、正方形の画像は縦と横のサイズが同じなので生成がスキップされる。だから処理ファイル数が違ってしまうのだな…。バグじゃなくてちゃんと正しい動作をしていた…。
いやはや、バグが出るわ出るわ…。親父さんはファイル管理が乱雑なので、お行儀が良い(?)自分の環境上では出てこなかった想定外の事態が次々に。
サブディレクトリやファイルを検索する際に、特に考えずに os.walk() を使ってしまって失敗した。サブディレクトリ内のサブディレクトリもリストアップしてしまって妙なページが出力されてしまう。os.walk() はディレクトリツリーを辿って全ファイルを検索する関数だから当たり前なのだけど…。os.listdir() を使って1階層だけ対象にするように変更した。
対象になる画像ファイルの拡張子はきっと ".jpg" だけだろうと決めつけて処理を書いていたけれど。親父さんの作ったサイトには ".JPG" もあって…。自分が画像ファイルを作成する時は必ず小文字の拡張子をつけているから、こんなトラップがあることに気づかなかった…。.lower() で小文字化して拡張子を比較することにした。
せっかくだからサムネイル画像を自動生成する処理を追加。画像処理ライブラリ Pillow の Image.resize() を使った。しかし、特定のフォルダを含めて処理させた時だけ、生成サムネイル画像数と、ページに列挙する画像ファイル数が違ってしまう…。何故。
原因が分かった。サムネイル画像が既にある場合、求めている画像サイズと同じなら再生成の必要無しと判断してスキップしているあたりが絡んでた。縦と横のどちらを基準にするかのチェックボックスを変えながら生成し直して動作確認してたけど、正方形の画像は縦と横のサイズが同じなので生成がスキップされる。だから処理ファイル数が違ってしまうのだな…。バグじゃなくてちゃんと正しい動作をしていた…。
◎ 文字コード判別について :
chardet パッケージを使えばテキストファイル内の文字コード判別ができるかなと期待していたけれど、試してみたら SJIS を Windows-1252 と誤認識する時があって…。
SJISで書いてるはずなのに、「None」になったり「Windows-1252」になったりする。
以下のページで解決策が紹介されてた。使われてる可能性が高い文字コードで順々に変換してみて、エラーが出てこなかったらその文字コードがおそらく正解だろうと推測する、という策らしい。
_chardetの文字コード誤判定を回避する ― Pythonで安全な文字コード判定ロジックの実装
以下のように試してみたら、たしかにそれらしく判別してくれた。この方法で行くことにしよう…。ありがたや。
"""
文字コード判定 chardet のサンプル
Windows11 x64 25H2 + Python 3.10.10 64bit
"""
import chardet
lst = [
"text_utf8.txt",
"text_sjis.txt",
"text_sjis2.txt",
]
for fn in lst:
print(f"Open {fn}")
with open(fn, "rb") as f:
c = f.read()
enc = chardet.detect(c)
print(enc)
print(enc["encoding"])
> python 01_chardet.py
Open text_utf8.txt
{'encoding': 'utf-8', 'confidence': 0.938125, 'language': ''}
utf-8
Open text_sjis.txt
{'encoding': None, 'confidence': 0.0, 'language': None}
None
Open text_sjis2.txt
{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}
Windows-1252
SJISで書いてるはずなのに、「None」になったり「Windows-1252」になったりする。
以下のページで解決策が紹介されてた。使われてる可能性が高い文字コードで順々に変換してみて、エラーが出てこなかったらその文字コードがおそらく正解だろうと推測する、という策らしい。
_chardetの文字コード誤判定を回避する ― Pythonで安全な文字コード判定ロジックの実装
以下のように試してみたら、たしかにそれらしく判別してくれた。この方法で行くことにしよう…。ありがたや。
"""
文字コードを指定しながらひとまずファイルを読み込んで、
エラーが出なかった文字コードを特定する方法。
Windows11 x64 25H2 + Python 3.10.10 64bit
"""
from pathlib import Path
import chardet
COMMON_ENCODINGS = ["utf-8", "CP932", "shift_jis", "euc_jp", "iso2022_jp"]
def detect_encoding(filepath: str) -> str:
"""
指定ファイルの文字コードを判定する
Args:
filepath (str): ファイルパス
Returns:
str: 文字コードを示す文字列
"""
fpath = Path(filepath)
content = fpath.read_bytes()
for enc in COMMON_ENCODINGS:
try:
content.decode(enc)
return enc
except UnicodeDecodeError:
continue
# 最終手段として chardet
result = chardet.detect(content)
return result["encoding"] or "utf-8"
lst = [
"text_utf8.txt",
"text_sjis.txt",
"text_sjis2.txt",
]
for fn in lst:
detected = detect_encoding(fn)
print(f"{fn} ... Detected encoding: {detected}")
[ ツッコむ ]
以上、1 日分です。