问题现象
脚本在本地跑得好好的,打包成 exe 之后,双击运行直接闪退。去命令行手动运行,看到了这个:
ModuleNotFoundError: No module named 'selenium.webdriver'
明明打包成功了,怎么还找不到模块?
根本原因
PyInstaller 的依赖分析是静态的——它只会打包代码中显式 import 的模块。但很多库用的是动态导入:
# selenium 内部会动态导入 webdriver 模块
# PyInstaller 分析不到,就不会打包进去
解决方案:--hidden-import
手动告诉 PyInstaller 这些"隐身"的依赖:
pyinstaller ^
--onefile ^
--hidden-import selenium.webdriver ^
--hidden-import selenium.webdriver.chrome.service ^
--hidden-import selenium.webdriver.common.by ^
MSDrpa.py
我遇到的完整 hidden-import 清单
这些是 MSD 自动化项目打包时踩出来的,供参考:
# Selenium 相关(最常见)
--hidden-import selenium.webdriver
--hidden-import selenium.webdriver.chrome.service
--hidden-import selenium.webdriver.chrome.options
--hidden-import selenium.webdriver.common.by
--hidden-import selenium.webdriver.support.ui
--hidden-import selenium.webdriver.support.expected_conditions
# 如果用到无头模式
--hidden-import selenium.webdriver.chrome.webdriver
# openpyxl(处理Excel)
--hidden-import openpyxl.cell._writer
--hidden-import openpyxl.worksheet._reader
# PIL/Pillow(截图用)
--hidden-import PIL._imaging
--hidden-import PIL._imagingtk
# 动态 import 的自定义模块
--hidden-import my_module.sub_module
更好的方案:用 .spec 文件
命令行参数太长,维护困难。改用 .spec 文件:
# msdrpa.spec
block_cipher = None
a = Analysis(
['MSDrpa.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[
'selenium.webdriver',
'selenium.webdriver.chrome.service',
'selenium.webdriver.common.by',
'selenium.webdriver.support.ui',
'selenium.webdriver.support.expected_conditions',
'openpyxl',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='MSDrpa',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True, # 改成 False 可隐藏命令行窗口
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
然后运行:
pyinstaller msdrpa.spec
✅ 调试技巧:打包时加
--debug all 可以看到详细的导入失败信息,比盲目加 hidden-import 高效得多。
终极武器:pyinstaller-hooks-contrib
很多常见库的 hook 已经有了,安装这个包可以自动处理很多 hidden-import:
pip install pyinstaller-hooks-contrib
安装后重新打包,Selenium、openpyxl 等常见库的 hidden-import 会自动处理,不需要手动指定。