4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【完全保存版】Python GUI→exe化で必ず出る25のエラーと解決法

Posted at

【完全保存版】Python GUI→exe化で必ず出る25のエラーと解決法

はじめに - なぜエラーが出るのか

PythonでGUIアプリを作成し、PyInstallerでexe化しようとすると、必ずと言っていいほどエラーに遭遇します。私自身も初めてexe化に挑戦したとき、10種類以上のエラーと格闘し、解決に丸2日かかった経験があります。

本記事では、PyInstallerを使ったexe化で必ず出る25のエラーパターンとその解決法を網羅的にまとめました。

PyInstallerでエラーが出やすい3つの理由

  1. 依存関係の自動検出が不完全

    • PyInstallerは静的解析でモジュールを検出しますが、動的インポートや隠れた依存関係は見逃します
  2. 実行環境の違い

    • 開発環境では動くのに、exeにすると相対パスやファイル配置が変わるため動かなくなります
  3. ライブラリ固有の問題

    • pandas、numpy、OpenCVなど、特定ライブラリは特別な設定が必要です

この記事の使い方

  • エラーメッセージで検索: 目次から該当するエラーに即ジャンプ
  • 予防チェックリスト: 開発前に確認して事前にエラーを防ぐ
  • フローチャート: エラーの切り分け方法を図解

対象読者・前提環境

  • Python初心者〜中級者
  • tkinter/PySimpleGUI等でGUI作成経験あり
  • Windows 10/11(一部macOS対応も記載)
  • Python 3.8以上
  • PyInstaller 5.0以上

目次

環境構築編(エラー1-5)

  1. pip install PyInstaller失敗
  2. Pythonバージョン非対応
  3. パス設定の問題
  4. 仮想環境認識エラー
  5. 権限不足エラー

ビルド実行編(エラー6-13)

  1. ModuleNotFoundError(基本パターン)
  2. ModuleNotFoundError(サブモジュール)
  3. FileNotFoundError(画像・データファイル)
  4. ImportError(隠れた依存関係)
  5. RecursionError
  6. UnicodeDecodeError
  7. specファイル構文エラー
  8. アイコンファイル形式エラー

実行時編(エラー14-20)

  1. ハンドル無効エラー
  2. DLLロードエラー
  3. 相対パス問題
  4. 一時ファイル展開エラー
  5. ウイルス対策ソフト誤検知
  6. 起動時クラッシュ
  7. GUI表示崩れ

特殊ライブラリ編(エラー21-25)

  1. pandas/numpy MKL問題
  2. OpenCV依存関係
  3. PyQt/PySide問題
  4. Pillow画像パス問題
  5. matplotlib表示エラー

環境構築編(エラー1-5)

エラー1: pip install PyInstaller失敗

症状

pip install pyinstaller
ERROR: Could not install packages due to an OSError

原因

  • Windows Defenderがインストールをブロック
  • ネットワーク制限(企業環境)
  • pipのバージョンが古い

解決法

解決策1: pipを最新化

python -m pip install --upgrade pip
pip install pyinstaller

解決策2: Windows Defenderを一時的に無効化

  1. Windowsセキュリティを開く
  2. ウイルスと脅威の防止 → 設定の管理
  3. リアルタイム保護を一時的にオフ
  4. インストール後、必ずオンに戻す

解決策3: ユーザーディレクトリにインストール

pip install --user pyinstaller

エラー2: Pythonバージョン非対応

症状

pyinstaller main.py
ERROR: This version of PyInstaller requires Python 3.8+

原因

  • PyInstaller 5.0以降はPython 3.7以下非対応
  • 複数のPythonバージョンが混在

解決法

解決策1: Pythonバージョン確認

python --version
# Python 3.7.x の場合は3.8以上にアップグレード

解決策2: 仮想環境で正しいバージョンを指定

# Python 3.10で仮想環境作成
python3.10 -m venv myenv
myenv\Scripts\activate  # Windows
source myenv/bin/activate  # macOS/Linux

解決策3: pyenvで複数バージョン管理

pyenv install 3.10.0
pyenv local 3.10.0

エラー3: パス設定の問題

症状

'pyinstaller' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

原因

  • PyInstallerがシステムPATHに登録されていない
  • 仮想環境のScriptsフォルダがPATHにない

解決法

解決策1: フルパスで実行

# Windows
python -m PyInstaller main.py

# または
C:\Users\YourName\AppData\Local\Programs\Python\Python310\Scripts\pyinstaller.exe main.py

解決策2: 環境変数PATHに追加(Windows)

  1. システムの詳細設定 → 環境変数
  2. Path変数を編集
  3. 以下を追加: C:\Users\YourName\AppData\Local\Programs\Python\Python310\Scripts

解決策3: 仮想環境を有効化してから実行

.venv\Scripts\activate
pyinstaller main.py

エラー4: 仮想環境認識エラー

症状

pyinstaller main.py
# グローバル環境のライブラリが使われてしまう
# または、ImportError: No module named 'xxx'

原因

  • 仮想環境がアクティブになっていない
  • 複数の仮想環境が混在

解決法

解決策1: 仮想環境を確実にアクティブ化

# Windows
.venv\Scripts\activate
# プロンプトに(.venv)が表示されることを確認

# macOS/Linux
source .venv/bin/activate

解決策2: 使用中のPythonパスを確認

where python  # Windows
which python  # macOS/Linux

# 仮想環境のパスが表示されることを確認

解決策3: deactivateしてから再度activate

deactivate
.venv\Scripts\activate
pip list  # インストール済みライブラリを確認

エラー5: 権限不足エラー

症状

pyinstaller main.py
PermissionError: [Errno 13] Permission denied: 'dist/main.exe'

原因

  • 前回ビルドしたexeが実行中
  • distフォルダが読み取り専用
  • ウイルス対策ソフトがファイルをロック

解決法

解決策1: 実行中のexeを終了

# タスクマネージャーでmain.exeを終了
# または
taskkill /F /IM main.exe  # Windows

解決策2: dist/buildフォルダを削除してから実行

rmdir /s /q dist build  # Windows
rm -rf dist build  # macOS/Linux

pyinstaller main.py --clean

解決策3: 管理者権限で実行

  • コマンドプロンプトを右クリック → 管理者として実行
  • その後pyinstallerコマンドを実行

ビルド実行編(エラー6-13)

エラー6: ModuleNotFoundError(基本パターン)

症状

# ビルドは成功するが、exeを実行すると
ModuleNotFoundError: No module named 'tkinter'
ModuleNotFoundError: No module named 'PIL'
ModuleNotFoundError: No module named 'requests'

原因

  • PyInstallerがモジュールを自動検出できていない
  • 動的インポート(importlib等)を使用している
  • サブモジュールの検出漏れ

解決法

解決策1: specファイルのhiddenimportsに追加

まず、specファイルを生成:

pyinstaller main.py --onefile
# main.specが生成される

main.specを編集:

a = Analysis(
    ['main.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=[
        'tkinter',
        'PIL',
        'PIL.Image',
        'requests',
    ],  # ここに追加
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=None,
    noarchive=False,
)

再ビルド:

pyinstaller main.spec --clean

解決策2: コマンドオプションで指定

pyinstaller main.py --onefile --hidden-import=PIL --hidden-import=requests

解決策3: よく漏れるモジュール一覧

hiddenimports=[
    # GUI関連
    'tkinter',
    'tkinter.ttk',
    'tkinter.filedialog',
    'tkinter.messagebox',
    
    # 画像処理
    'PIL',
    'PIL.Image',
    'PIL.ImageTk',
    'PIL.ImageDraw',
    
    # データ処理
    'pandas',
    'numpy',
    'openpyxl',
    'xlrd',
    
    # Web関連
    'requests',
    'urllib3',
    'certifi',
]

エラー7: ModuleNotFoundError(サブモジュール)

症状

# 特定のサブモジュールだけエラー
ModuleNotFoundError: No module named 'pandas.io.excel'
ModuleNotFoundError: No module named 'plotly.validators.layout'

原因

  • 親モジュールは検出されているが、サブモジュールが漏れている
  • plotly、pandas等は内部構造が複雑で検出漏れが多発

解決法

解決策1: サブモジュールを個別指定

hiddenimports=[
    'pandas',
    'pandas.io',
    'pandas.io.excel',
    'pandas.io.excel._xlrd',
    'pandas.io.excel._openpyxl',
]

解決策2: ワイルドカード的に全サブモジュール追加(plotlyの例)

# 全サブモジュールを取得するスクリプト
import pkgutil
import plotly

def get_all_submodules(package):
    submodules = []
    for importer, modname, ispkg in pkgutil.walk_packages(
        path=package.__path__,
        prefix=package.__name__ + '.',
    ):
        submodules.append(modname)
    return submodules

plotly_modules = get_all_submodules(plotly)
print(plotly_modules)
# この結果をhiddenimportsにコピー

解決策3: よく問題になるサブモジュール一覧

hiddenimports=[
    # pandas関連
    'pandas.io.formats.excel',
    'pandas.plotting._matplotlib',
    
    # plotly関連(大量)
    'plotly.validators',
    'plotly.validators.layout',
    'plotly.graph_objs',
    
    # sklearn関連
    'sklearn.utils._cython_blas',
    'sklearn.neighbors.typedefs',
    'sklearn.tree._utils',
]

エラー8: FileNotFoundError(画像・データファイル)

症状

# exeを実行すると
FileNotFoundError: [Errno 2] No such file or directory: 'icon.png'
FileNotFoundError: [Errno 2] No such file or directory: 'data/config.json'

原因

  • 画像やデータファイルがexeに同梱されていない
  • 相対パスの基準がexe実行時とPython実行時で異なる

解決法

解決策1: specファイルのdatasに追加

a = Analysis(
    ['main.py'],
    datas=[
        ('icon.png', '.'),  # (元のパス, exe内の配置先)
        ('data/config.json', 'data'),
        ('images/*.png', 'images'),  # フォルダごと
    ],
)

解決策2: コマンドオプションで指定

pyinstaller main.py --onefile --add-data "icon.png;." --add-data "data;data"
# Windowsは ; 、macOS/Linuxは : を使用

解決策3: 実行時パスを動的に取得するコード

import sys
import os

def resource_path(relative_path):
    """PyInstallerでexe化した際のリソースパスを取得"""
    try:
        # PyInstallerで作成された一時フォルダ
        base_path = sys._MEIPASS
    except Exception:
        # 通常のPython実行時
        base_path = os.path.abspath(".")
    
    return os.path.join(base_path, relative_path)

# 使用例
icon_path = resource_path('icon.png')
image = Image.open(icon_path)

解決策4: フォルダ構造を保持して配置

プロジェクト/
├─ main.py
├─ images/
│  ├─ icon.png
│  └─ logo.png
└─ data/
   └─ config.json

# specファイルで
datas=[
    ('images', 'images'),
    ('data', 'data'),
]

# コード内で
icon_path = resource_path('images/icon.png')

エラー9: ImportError(隠れた依存関係)

症状

ImportError: DLL load failed while importing _imaging: 指定されたモジュールが見つかりません。
ImportError: cannot import name 'soft_unicode' from 'markupsafe'

原因

  • ライブラリが内部で別のライブラリに依存している
  • DLLファイルが不足している
  • バージョン不整合

解決法

解決策1: 依存関係を明示的にインストール

# Pillowの例
pip install pillow
pip install pillow --force-reinstall

# 依存関係を確認
pip show pillow

解決策2: 問題のあるライブラリを再インストール

pip uninstall markupsafe
pip install markupsafe==2.0.1  # 安定バージョンを指定

解決策3: hiddenimportsに依存ライブラリを追加

hiddenimports=[
    'PIL._tkinter_finder',  # Pillow + tkinterの場合
    'pkg_resources.py2_warn',  # setuptools関連
]

解決策4: バイナリファイルを明示的に含める

a = Analysis(
    ['main.py'],
    binaries=[
        ('C:/path/to/library.dll', '.'),
    ],
)

エラー10: RecursionError

症状

RecursionError: maximum recursion depth exceeded
# ビルド中に発生

原因

  • PyInstaller内部で再帰処理が深すぎる
  • 循環インポートがある
  • 複雑なライブラリ依存関係

解決法

解決策1: 再帰回数上限を増やす

main.pyの先頭に追加:

import sys
sys.setrecursionlimit(5000)  # デフォルトは1000

解決策2: specファイルで設定

import sys
sys.setrecursionlimit(5000)

a = Analysis(
    ['main.py'],
    # 以下通常通り
)

解決策3: 循環インポートを解消

# 悪い例
# module_a.py
import module_b

# module_b.py
import module_a  # 循環インポート

# 良い例:必要な箇所でのみインポート
# module_b.py
def some_function():
    import module_a  # 関数内でインポート
    module_a.do_something()

エラー11: UnicodeDecodeError

症状

UnicodeDecodeError: 'cp932' codec can't decode byte 0x99 in position 123
# ビルド時または実行時に発生

原因

  • ソースコードやデータファイルに日本語が含まれる
  • Windowsのデフォルトエンコーディング(cp932)と不一致

解決法

解決策1: ファイル先頭にエンコーディング宣言

# -*- coding: utf-8 -*-
import tkinter as tk
# 以下コード

解決策2: ファイル読み込み時にエンコーディング指定

# 悪い例
with open('data.txt', 'r') as f:
    data = f.read()

# 良い例
with open('data.txt', 'r', encoding='utf-8') as f:
    data = f.read()

解決策3: PyInstallerコマンドでエンコーディング指定

set PYTHONIOENCODING=utf-8
pyinstaller main.py --onefile

解決策4: 環境変数を設定

import os
os.environ['PYTHONIOENCODING'] = 'utf-8'

エラー12: specファイル構文エラー

症状

pyinstaller main.spec
SyntaxError: invalid syntax

原因

  • specファイル編集時の構文ミス
  • カンマ、カッコの対応ミス
  • インデントの誤り

解決法

解決策1: 基本的なspecファイル構造を確認

# -*- mode: python ; coding: utf-8 -*-

a = Analysis(
    ['main.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=None,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=None)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='main',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,  # GUIの場合False
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

解決策2: よくあるミス

# ミス1: カンマ忘れ
hiddenimports=[
    'tkinter'
    'PIL'  # ← カンマがない!
]

# 正しい
hiddenimports=[
    'tkinter',
    'PIL',
]

# ミス2: パスのエスケープ
datas=[
    ('C:\images\icon.png', '.')  # ← \が特殊文字として解釈される
]

# 正しい
datas=[
    (r'C:\images\icon.png', '.'),  # rをつける
    # または
    ('C:/images/icon.png', '.'),  # スラッシュ使用
]

解決策3: specファイルを再生成

# 既存のspecを削除
del main.spec

# 再生成
pyinstaller main.py --onefile --noconsole

# 再度編集

エラー13: アイコンファイル形式エラー

症状

pyinstaller main.py --icon=icon.png
IOError: cannot identify image file 'icon.png'

原因

  • PNG形式を指定している(icoファイルが必要)
  • アイコンファイルが壊れている
  • ファイルサイズが大きすぎる

解決法

解決策1: PNGをICOに変換

from PIL import Image

# PNG画像を読み込み
img = Image.open('icon.png')

# ICOファイルとして保存
img.save('icon.ico', format='ICO', sizes=[(256, 256)])

解決策2: オンラインツールで変換

解決策3: 複数サイズのアイコンを含める

from PIL import Image

img = Image.open('icon.png')
img.save('icon.ico', format='ICO', sizes=[
    (16, 16),
    (32, 32),
    (48, 48),
    (64, 64),
    (256, 256)
])

解決策4: specファイルでアイコン指定

exe = EXE(
    # ...
    icon='icon.ico',  # .icoファイルを指定
    # ...
)

実行時編(エラー14-20)

エラー14: ハンドル無効エラー

症状

OSError: [WinError 6] ハンドルが無効です。
# --noconsole + --onefile の組み合わせで発生

原因

  • --noconsole--onefileを同時使用時、subprocessがstdinを見失う
  • テキスト処理ライブラリ(pytesseract等)で頻発

解決法

解決策1: subprocess呼び出しにstdin=DEVNULL追加

エラーが出ているライブラリの該当ファイルを修正:

# 例: pytesseractのtesseract.py
import subprocess

# 修正前
proc = subprocess.Popen(
    command,
    stdout=subprocess.PIPE,
    stderr=subprocess.STDOUT
)

# 修正後
proc = subprocess.Popen(
    command,
    stdout=subprocess.PIPE,
    stderr=subprocess.STDOUT,
    stdin=subprocess.DEVNULL  # これを追加
)

解決策2: 自分のコードでsubprocessを使っている場合

import subprocess

# 必ずstdin=subprocess.DEVNULLを指定
result = subprocess.run(
    ['command', 'arg'],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    stdin=subprocess.DEVNULL  # 追加
)

解決策3: --onedirモードで回避

# --onefileを使わない
pyinstaller main.py --noconsole
# distフォルダ内に複数ファイルが生成されるが、エラーは出ない

エラー15: DLLロードエラー

症状

ImportError: DLL load failed: 指定されたモジュールが見つかりません。
# numpy、scipy、OpenCV等で頻発

原因

  • 必要なDLLファイルがexeに同梱されていない
  • Visual C++ 再頒布可能パッケージが未インストール
  • 32bit/64bitの不一致

解決法

解決策1: Visual C++ 再頒布可能パッケージをインストール

配布先PCで必要:

解決策2: DLLを明示的に同梱

import numpy
import os

# numpyのDLLパスを取得
numpy_path = numpy.__path__[0]
dll_path = os.path.join(numpy_path, '.libs')

# specファイルで
binaries=[
    (dll_path, '.libs'),
]

解決策3: Anaconda環境の場合

# conda環境から必要なDLLをコピー
# C:\Users\YourName\anaconda3\Library\bin\*.dll

解決策4: Pythonビット数確認

import platform
print(platform.architecture())
# ('64bit', 'WindowsPE') であることを確認

エラー16: 相対パス問題

症状

# 開発時は動くが、exeにすると
FileNotFoundError: [Errno 2] No such file or directory: './data/config.json'

原因

  • カレントディレクトリがexe実行時とPython実行時で異なる
  • PyInstallerは一時フォルダに展開してから実行する

解決法

解決策1: 実行ファイルの場所を基準にする

import sys
import os

def get_base_path():
    """実行ファイルのディレクトリを取得"""
    if getattr(sys, 'frozen', False):
        # exe化されている場合
        return os.path.dirname(sys.executable)
    else:
        # Python実行の場合
        return os.path.dirname(os.path.abspath(__file__))

# 使用例
base_path = get_base_path()
config_path = os.path.join(base_path, 'data', 'config.json')

with open(config_path, 'r') as f:
    config = json.load(f)

解決策2: リソースパス取得関数(エラー8の再掲)

def resource_path(relative_path):
    """PyInstallerの一時フォルダまたは開発時のパスを返す"""
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# 使用例
config_path = resource_path('data/config.json')

解決策3: 絶対パスは避ける

# 悪い例
image = Image.open('C:/Users/YourName/project/icon.png')

# 良い例
image = Image.open(resource_path('icon.png'))

エラー17: 一時ファイル展開エラー

症状

# exeを起動すると
Failed to execute script 'main' due to unhandled exception!
[Errno 28] No space left on device

原因

  • --onefileで作成したexeは起動時に一時フォルダへ展開
  • 一時フォルダの容量不足
  • ウイルス対策ソフトが展開をブロック

解決法

解決策1: 一時フォルダをクリーンアップ

# Windowsの一時フォルダ
%TEMP%
C:\Users\YourName\AppData\Local\Temp

# _MEIから始まるフォルダを削除

解決策2: --onedirモードを使用

# 一時展開が不要になる
pyinstaller main.py --noconsole
# distフォルダごと配布

解決策3: 展開先を指定

# specファイルで
exe = EXE(
    # ...
    runtime_tmpdir='./temp',  # 展開先を指定
    # ...
)

解決策4: ディスク容量確保

  • Cドライブの空き容量を確認
  • 不要ファイルを削除
  • 一時フォルダを別ドライブに変更

エラー18: ウイルス対策ソフト誤検知

症状

# exeを実行すると
Windows Defender: トロイの木馬として検出されました
# または起動後すぐに強制終了

原因

  • PyInstallerで作成したexeは、ウイルス対策ソフトに誤検知されやすい
  • 特に--onefileモードは自己展開型のため疑われる
  • UPX圧縮を使うとさらに誤検知率が上がる

解決法

解決策1: Windows Defenderの除外設定

1. Windowsセキュリティを開く
2. ウイルスと脅威の防止 → 設定の管理
3. 除外 → 除外の追加または削除
4. exeファイルまたはフォルダを追加

解決策2: UPX圧縮を無効化

pyinstaller main.py --onefile --noupx

解決策3: コード署名証明書を取得

# 有料だが信頼性向上
# DigiCert、Sectigo等から購入
# signtool.exeで署名

signtool sign /f certificate.pfx /p password main.exe

解決策4: --onedirモードで配布

# 誤検知されにくい
pyinstaller main.py --noconsole

解決策5: VirusTotalでスキャン結果を確認


エラー19: 起動時クラッシュ

症状

# exeをダブルクリックしても一瞬で消える
# またはエラーダイアログなしで終了

原因

  • 起動直後のエラーがコンソール非表示で見えない
  • 初期化処理での例外
  • 必須ファイルの不足

解決法

解決策1: --consoleモードでデバッグ

# コンソールを表示してエラー確認
pyinstaller main.py --onefile --console

# エラーメッセージが表示されるようになる

解決策2: ログファイル出力を追加

import logging
import sys
import os

# ログ設定
log_file = os.path.join(os.path.dirname(sys.executable), 'app.log')
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(log_file, encoding='utf-8'),
        logging.StreamHandler()
    ]
)

# メイン処理をtry-exceptで囲む
try:
    logging.info('アプリケーション起動')
    # メイン処理
    main()
except Exception as e:
    logging.exception('エラーが発生しました')
    raise

解決策3: 段階的にコメントアウトして原因特定

def main():
    print("Step 1")  # ここまで実行されるか確認
    # import heavy_library  # 一旦コメントアウト
    
    print("Step 2")
    # gui_window = create_gui()  # 一旦コメントアウト
    
    print("Step 3")
    # run_main_logic()  # 一旦コメントアウト

解決策4: 例外ハンドラーでメッセージボックス表示

import tkinter as tk
from tkinter import messagebox
import traceback

def show_error(e):
    """エラーをGUIで表示"""
    root = tk.Tk()
    root.withdraw()
    error_msg = f"エラーが発生しました:\n\n{str(e)}\n\n{traceback.format_exc()}"
    messagebox.showerror("エラー", error_msg)
    root.destroy()

try:
    main()
except Exception as e:
    show_error(e)

エラー20: GUI表示崩れ

症状

# exeを実行すると
# - ボタンが見えない
# - 画像が表示されない
# - フォントが変わる
# - レイアウトがずれる

原因

  • 画像ファイルのパスが通っていない
  • フォントファイルが不足
  • DPIスケーリングの影響
  • tkinterのバージョン差異

解決法

解決策1: 画像パスを動的取得に変更

# 悪い例
icon = PhotoImage(file='icon.png')

# 良い例
def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

icon = PhotoImage(file=resource_path('icon.png'))

解決策2: DPI対応

import ctypes

# Windows 10/11でDPI認識を有効化
try:
    ctypes.windll.shcore.SetProcessDpiAwareness(1)
except:
    pass

root = tk.Tk()

解決策3: フォント明示指定

# システムフォントに依存しない
import tkinter.font as tkFont

# 明示的にフォント指定
default_font = tkFont.Font(family='メイリオ', size=10)
label = tk.Label(root, text='テスト', font=default_font)

解決策4: レイアウト固定

# サイズ可変を避ける
root = tk.Tk()
root.geometry('800x600')
root.resizable(False, False)  # サイズ変更不可

# 絶対座標でウィジェット配置
button.place(x=100, y=50, width=200, height=40)

特殊ライブラリ編(エラー21-25)

エラー21: pandas/numpy MKL問題

症状

# exeファイルが300MB以上になる
# または
ImportError: DLL load failed: 指定されたモジュールが見つかりません。

原因

  • pandas/numpyはIntel MKL(数学演算ライブラリ)を内包
  • MKLだけで100-200MB以上
  • 不要な場合も強制的に含まれる

解決法

解決策1: MKLを除外(軽量化)

specファイルを編集:

# -*- mode: python ; coding: utf-8 -*-

a = Analysis(
    ['main.py'],
    # 通常の設定
)

# MKL除外コード追加
def remove_mkl(binaries_list):
    """MKL関連ファイルを除外"""
    return [
        (dest, src, kind)
        for dest, src, kind in binaries_list
        if not dest.startswith('mkl')
    ]

a.binaries = remove_mkl(a.binaries)

pyz = PYZ(a.pure, a.zipped_data)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='main',
    # 以下通常通り
)

解決策2: より詳細なMKL除外

def remove_from_list(input_list, keywords):
    """キーワードを含むファイルを除外"""
    output_list = []
    for item in input_list:
        name, src, kind = item
        should_exclude = False
        for keyword in keywords:
            if keyword in name.lower():
                should_exclude = True
                break
        if not should_exclude:
            output_list.append(item)
    return output_list

# 除外キーワード
exclude_keywords = ['mkl', 'libopenblas', 'libblas', 'liblapack']
a.binaries = remove_from_list(a.binaries, exclude_keywords)

解決策3: numpy-baseをインストール(軽量版)

pip uninstall numpy
pip install numpy-base  # MKLなしバージョン
# ただし計算速度は低下

解決策4: 実測比較

MKL込み: 約320MB
MKL除外: 約35MB
削減率: 約89%

エラー22: OpenCV依存関係

症状

ModuleNotFoundError: No module named 'cv2'
# または
ImportError: DLL load failed while importing cv2

原因

  • OpenCVは依存関係が複雑
  • 複数のDLLファイルが必要
  • バージョンによって必要ファイルが異なる

解決法

解決策1: hiddenimportsに追加

hiddenimports=[
    'cv2',
    'numpy',
    'numpy.core',
]

解決策2: OpenCVのDLLを明示的に含める

import cv2
import os

cv2_path = os.path.dirname(cv2.__file__)

# specファイルで
binaries=[
    (os.path.join(cv2_path, 'opencv_ffmpeg*.dll'), '.'),
]

datas=[
    (cv2_path, 'cv2'),
]

解決策3: opencv-python-headlessを使用

pip uninstall opencv-python
pip install opencv-python-headless
# GUI機能なし、軽量版

解決策4: PyInstallerのhookファイル作成

# hook-cv2.py を作成
from PyInstaller.utils.hooks import collect_data_files, collect_dynamic_libs

datas = collect_data_files('cv2')
binaries = collect_dynamic_libs('cv2')

specファイルで指定:

a = Analysis(
    ['main.py'],
    hookspath=['./hooks'],  # hook-cv2.pyがあるフォルダ
)

エラー23: PyQt/PySide問題

症状

ModuleNotFoundError: No module named 'PyQt5.QtCore'
# または
ImportError: DLL load failed: 指定されたプロシージャが見つかりません。

原因

  • PyQt5/PySide2は巨大なライブラリ
  • プラグインファイルが多数必要
  • Qt特有の依存関係

解決法

解決策1: hiddenimportsに全モジュール追加

hiddenimports=[
    'PyQt5',
    'PyQt5.QtCore',
    'PyQt5.QtGui',
    'PyQt5.QtWidgets',
    'PyQt5.sip',
]

解決策2: PyQt5専用のhookを使用

# PyInstallerは自動でPyQt5を検出するはずだが、
# 手動で指定する場合

pyinstaller main.py --hidden-import=PyQt5 --hidden-import=PyQt5.sip

解決策3: プラグインフォルダを含める

import PyQt5
import os

qt_plugin_path = os.path.join(os.path.dirname(PyQt5.__file__), 'Qt5', 'plugins')

# specファイルで
datas=[
    (qt_plugin_path, 'PyQt5/Qt5/plugins'),
]

解決策4: 軽量化したい場合

# 不要なQtモジュールを除外
a = Analysis(
    ['main.py'],
    excludes=[
        'PyQt5.QtWebEngine',  # Webエンジン不要なら
        'PyQt5.QtBluetooth',
        'PyQt5.Qt3D',
    ],
)

エラー24: Pillow画像パス問題

症状

PIL.UnidentifiedImageError: cannot identify image file
# または
FileNotFoundError: [Errno 2] No such file or directory: 'image.png'

原因

  • 画像ファイルがexeに含まれていない
  • パス指定が相対パス
  • PIL内部のフォントファイルが不足

解決法

解決策1: 画像ファイルをdatasに追加

# specファイルで
datas=[
    ('images/*.png', 'images'),
    ('images/*.jpg', 'images'),
]

解決策2: リソースパス取得

from PIL import Image
import sys
import os

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# 使用例
image_path = resource_path('images/sample.png')
img = Image.open(image_path)

解決策3: PILフォントファイルの問題

# カスタムフォント使用時
from PIL import ImageFont

# 悪い例
font = ImageFont.truetype('arial.ttf', 20)

# 良い例
font_path = resource_path('fonts/arial.ttf')
font = ImageFont.truetype(font_path, 20)

# specファイルで
datas=[
    ('fonts/*.ttf', 'fonts'),
]

解決策4: 画像をBase64エンコードして埋め込み

import base64
from io import BytesIO
from PIL import Image

# 画像をBase64に変換(事前処理)
with open('icon.png', 'rb') as f:
    img_data = base64.b64encode(f.read()).decode()

# コード内に埋め込み
IMG_DATA = 'iVBORw0KGgoAAAANSUhEUgAA...'  # Base64文字列

# 使用時
img_bytes = base64.b64decode(IMG_DATA)
img = Image.open(BytesIO(img_bytes))

エラー25: matplotlib表示エラー

症状

ImportError: No module named 'matplotlib.backends.backend_tkagg'
# または
RuntimeError: Could not find the matplotlib data files

原因

  • matplotlibのバックエンドモジュールが欠落
  • データファイル(フォント等)が不足
  • tkinterバックエンドの依存関係

解決法

解決策1: hiddenimportsに追加

hiddenimports=[
    'matplotlib',
    'matplotlib.backends.backend_tkagg',
    'matplotlib.backends.backend_agg',
    'matplotlib.figure',
]

解決策2: matplotlibのデータファイルを含める

import matplotlib
import os

mpl_data_path = os.path.join(matplotlib.__path__[0], 'mpl-data')

# specファイルで
datas=[
    (mpl_data_path, 'matplotlib/mpl-data'),
]

解決策3: バックエンドを明示指定

import matplotlib
matplotlib.use('TkAgg')  # または 'Agg'
import matplotlib.pyplot as plt

解決策4: Agグバックエンドで画像保存のみ

# GUI表示せず、画像ファイル保存のみ
import matplotlib
matplotlib.use('Agg')  # GUIなし
import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 5, 6])
plt.savefig('output.png')
# plt.show() は使わない

解決策5: 完全なhiddenimports

hiddenimports=[
    'matplotlib',
    'matplotlib.backends',
    'matplotlib.backends.backend_tkagg',
    'matplotlib.backends.backend_agg',
    'matplotlib.figure',
    'matplotlib.pyplot',
    'tkinter',
    'tkinter.filedialog',
]

エラー解決フローチャート

エラー診断3ステップ

ステップ1: エラー発生タイミングの特定

# Q1: pipインストール時?
→ 環境構築編(エラー1-5)

# Q2: pyinstallerコマンド実行時?
→ ビルド実行編(エラー6-13)

# Q3: exeファイル実行時?
→ 実行時編(エラー14-20)

ステップ2: エラーメッセージのキーワード検索

"ModuleNotFoundError" → エラー6, 7
"FileNotFoundError" → エラー8, 24
"DLL load failed" → エラー15, 21, 22
"ハンドル無効" → エラー14
"RecursionError" → エラー10

ステップ3: 使用ライブラリの確認

# requirements.txtを確認
pandas  エラー21
numpy  エラー21
opencv-python  エラー22
PyQt5  エラー23
pillow  エラー24
matplotlib  エラー25

予防チェックリスト20項目

開発前チェック(7項目)

  • Python 3.8以上をインストール済み
  • 仮想環境を作成して開発を開始
    python -m venv .venv
    .venv\Scripts\activate
    
  • requirements.txtで依存関係を管理
    pip freeze > requirements.txt
    
  • ファイルパスは全て相対パスで記述
  • 画像・データファイルは専用フォルダに整理
    project/
    ├─ main.py
    ├─ images/
    └─ data/
    
  • コード内の日本語はUTF-8で保存
    # -*- coding: utf-8 -*-
    
  • subprocessを使う場合はstdin=DEVNULL指定

ビルド前チェック(8項目)

  • 仮想環境がアクティブか確認
    where python  # 仮想環境のパスが表示されるか
    
  • 不要なライブラリをアンインストール
    pip list  # 使っていないライブラリを確認
    pip uninstall [不要なライブラリ]
    
  • PyInstallerを最新版に更新
    pip install --upgrade pyinstaller
    
  • アイコンファイルは.ico形式か確認
  • 前回のdist/buildフォルダを削除
    rmdir /s /q dist build
    
  • --consoleモードで一度ビルドしてエラー確認
    pyinstaller main.py --console
    
  • エラーが出た場合はspecファイルを編集
  • hiddenimports/datasを適切に設定

配布前チェック(5項目)

  • 別のPCで動作確認(可能なら)
  • Windows Defenderでスキャン
  • README.txtを同梱
    • 使い方
    • 必要な環境
    • トラブルシューティング
  • Visual C++ 再頒布可能パッケージの案内
  • バージョン番号をファイル名に含める
    MyApp_v1.0.0.exe
    

よくある質問TOP10

Q1: exeファイルが500MBを超えてしまう

A: MKL除外、仮想環境最適化で大幅削減可能

# specファイルでMKL除外(エラー21参照)
def remove_mkl(binaries_list):
    return [(d, s, k) for d, s, k in binaries_list if not d.startswith('mkl')]

a.binaries = remove_mkl(a.binaries)

# 実測: 320MB → 35MB(約90%削減)

Q2: exe起動に30秒以上かかる

A: --onedirモードに変更で劇的に改善

# --onefileは起動時に展開するため遅い
pyinstaller main.py --onefile  # 起動30秒

# --onedirは展開不要で高速
pyinstaller main.py  # 起動3秒

Q3: 他のPCで「DLLがない」と言われる

A: Visual C++ 再頒布可能パッケージをインストール

配布先PCで必要:
https://aka.ms/vs/17/release/vc_redist.x64.exe

Q4: Windows Defenderがウイルスと判定

A: 除外設定、または--noupxオプション

pyinstaller main.py --onefile --noupx

Q5: 画像が表示されない

A: リソースパス取得関数を使用(エラー8, 16参照)

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

img = Image.open(resource_path('icon.png'))

Q6: エラーメッセージが見えない

A: --consoleモードで実行、またはログ出力

pyinstaller main.py --console
import logging
logging.basicConfig(filename='app.log', level=logging.DEBUG)

Q7: pandas/numpyでエラーが出る

A: MKL問題またはhiddenimports不足

# specファイルで
hiddenimports=[
    'pandas',
    'pandas.io.formats.excel',
    'numpy',
    'numpy.core',
]

# MKL除外(エラー21参照)

Q8: macOS/Linuxでも動かしたい

A: 各OS環境で個別にビルドが必要

# Windows用exeはWindowsでビルド
# macOS用appはmacOSでビルド
# Linux用はLinuxでビルド

# クロスコンパイルは不可

Q9: アップデート配布方法は?

A: GitHub Releaseまたはバージョン管理機能実装

# 簡易バージョンチェック
import requests

CURRENT_VERSION = '1.0.0'
UPDATE_URL = 'https://api.github.com/repos/user/repo/releases/latest'

def check_update():
    response = requests.get(UPDATE_URL)
    latest = response.json()['tag_name']
    if latest > CURRENT_VERSION:
        print(f'新バージョン{latest}があります')

Q10: specファイルとは?編集必須?

A: ビルド設定ファイル。エラー時のみ編集

# 初回は自動生成される
pyinstaller main.py

# エラーが出たら編集
# main.spec を開いてhiddenimports等を追加
# 次回から
pyinstaller main.spec --clean

トラブルシューティング実践例

実例1: pandas使用ツールのエラー完全解決

状況: Excelファイル処理ツールをexe化したい

遭遇エラー:

  1. ModuleNotFoundError: pandas.io.excel
  2. exeが320MB
  3. 起動に25秒かかる

解決手順:

# ステップ1: hiddenimports追加
hiddenimports=[
    'pandas',
    'pandas.io.excel._xlrd',
    'pandas.io.excel._openpyxl',
    'openpyxl',
    'xlrd',
]

# ステップ2: MKL除外で軽量化
def remove_mkl(binaries):
    return [(d, s, k) for d, s, k in binaries if 'mkl' not in d.lower()]

a.binaries = remove_mkl(a.binaries)

# ステップ3: --onedirで高速化
pyinstaller main.spec  # --onefileを外す

# 結果:
# ファイルサイズ: 320MB → 45MB
# 起動時間: 25秒 → 3秒

実例2: 画像処理アプリの完全修正

状況: Pillow + OpenCVで画像編集ツール

遭遇エラー:

  1. FileNotFoundError: icon.png
  2. ImportError: cv2 DLL load failed
  3. GUI表示崩れ

解決手順:

# main.py
import sys
import os
from PIL import Image
import cv2
import tkinter as tk

def resource_path(relative_path):
    """リソースパス取得"""
    try:
        base_path = sys._MEIPASS
    except:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# 画像読み込み修正
icon_path = resource_path('images/icon.png')
img = Image.open(icon_path)

# DPI対応
import ctypes
try:
    ctypes.windll.shcore.SetProcessDpiAwareness(1)
except:
    pass

# specファイル
datas=[
    ('images', 'images'),
]

hiddenimports=[
    'cv2',
    'PIL',
    'PIL._tkinter_finder',
]

# OpenCVのDLL追加
import cv2
cv2_path = os.path.dirname(cv2.__file__)
binaries=[
    (os.path.join(cv2_path, '*.dll'), '.'),
]

# 結果: すべてのエラー解消

まとめ - エラーゼロへのロードマップ

重要ポイント再確認

  1. 仮想環境は必須

    • 無駄なライブラリ同梱を防ぐ
    • ファイルサイズ大幅削減
  2. 相対パスは動的取得

    • resource_path関数を活用
    • sys._MEIP

エラーはわからないと本当に辛いものでした。少しでも多くのみなさんのひとつのエラーに役に立てれば幸いです。
今後ともよろしくお願いします。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?