Python:排除 Pyinstaller 模块

26 投票
5 回答
47972 浏览
提问于 2025-04-16 11:10

我开始使用Pyinstaller来替代Py2Exe。不过我很快就遇到了一个问题。我该如何排除那些我不想要的模块?还有,我怎么能查看哪些模块被包含在生成的单个可执行文件里呢?

我可以从Python安装目录的DLL文件夹中删除一些pyddll文件,这样Pyinstaller就找不到它们,也就不会把它们包含进去了。不过我不想对所有模块都这么做,因为那样会非常麻烦。

我尝试过编辑Pyinstaller生成的spec文件。

a.binaries - [('ssl','pydoc',)],

但是文件的大小没有变化,所以我觉得这样并没有奏效。

那么,我该如何查看Pyinstaller包含了哪些模块,又该如何排除那些我不想要的模块呢?

5 个回答

7

你可以试试这个,效果比 .bat 脚本好很多:

# Just add or remove values to this list based on the imports you don't want : )
excluded_modules = [
    'numpy',
    'jedi',
    'PIL',
    'psutil',
    'tk',
    'ipython',
    'tcl',
    'tcl8',
    'tornado'
]

append_string = ''
for mod in excluded_modules:
    append_string += f' --exclude-module {mod}'

# Run the shell command with all the exclude module parameters
os.system(f'pyinstaller myfile.py --noconfirm {append_string}')

希望你觉得这个有用!

16

虽然可能有更好的解决方案,但还有一种方法:

你可以在使用'pyinstaller'命令时加上'--exclude-module'这个选项,不过如果你要排除很多模块,这个方法会比较麻烦。

为了简化这个过程,你可以写一个批处理脚本,把所有需要跳过的库列在里面,这样就可以反复使用了。

像这样:

@echo off

pyinstaller --onefile a.py --exclude-module matplotlib ^
                           --exclude-module scipy ^
                           --exclude-module setuptools ^
                           --exclude-module hook ^
                           --exclude-module distutils ^
                           --exclude-module site ^
                           --exclude-module hooks ^
                           --exclude-module tornado ^
                           --exclude-module PIL ^
                           --exclude-module PyQt4 ^
                           --exclude-module PyQt5 ^
                           --exclude-module pydoc ^
                           --exclude-module pythoncom ^
                           --exclude-module pytz ^
                           --exclude-module pywintypes ^
                           --exclude-module sqlite3 ^
                           --exclude-module pyz ^
                           --exclude-module pandas ^
                           --exclude-module sklearn ^
                           --exclude-module scapy ^
                           --exclude-module scrapy ^
                           --exclude-module sympy ^
                           --exclude-module kivy ^
                           --exclude-module pyramid ^
                           --exclude-module opencv ^
                           --exclude-module tensorflow ^
                           --exclude-module pipenv ^
                           --exclude-module pattern ^
                           --exclude-module mechanize ^
                           --exclude-module beautifulsoup4 ^
                           --exclude-module requests ^
                           --exclude-module wxPython ^
                           --exclude-module pygi ^
                           --exclude-module pillow ^
                           --exclude-module pygame ^
                           --exclude-module pyglet ^
                           --exclude-module flask ^
                           --exclude-module django ^
                           --exclude-module pylint ^
                           --exclude-module pytube ^
                           --exclude-module odfpy ^
                           --exclude-module mccabe ^
                           --exclude-module pilkit ^
                           --exclude-module six ^
                           --exclude-module wrapt ^
                           --exclude-module astroid ^
                           --exclude-module isort

或者你也可以选择重新安装一个新的Python,只需在安装时更改新Python的路径即可。

30

这里简单总结一下我使用的选项。

PyInstaller 的 TOC(表格内容)是,正如文档所说的:

TOC 看起来像是一个包含元组的列表,格式为 (名称, 路径, 类型代码)。实际上,它是一个有序集合,而不是列表。TOC 中没有重复项,唯一性仅基于名称。

换句话说,就是:

a_toc = [('uname1','/path/info','BINARY'),('uname2','/path/to','EXTENSION')...]

所以,在你的 .spec 文件中 - 一旦你得到了脚本的分析结果 - 你可以进一步修改相应的 TOC,方法有:

  • 对于 特定 的文件/模块,可以使用差集 (-) 和交集 (+) 操作来修改 TOC。

  • 对于添加/删除 文件/模块 的列表,可以遍历 TOC,并使用模式匹配代码进行比较。

(* 顺便提一下,要使差集有效,似乎你必须明确转换为 TOC(),并且注意到唯一定义集合元素的只有名称,因此你只需要指定名称 - 比如 ('sqlite3', None, None) 等等。)

下面是一个示例(取自一个 .spec 文件),在这个示例中 - 不论好坏 - 我删除了所有关于 scipy、IPython 和 zmq 的引用;删除了特定的 sqlite、tcl/tk 和 ssl 的 .DLL 文件;插入了一个缺失的 opencv .DLL;最后,除了 matplotlib 的文件夹外,删除了所有找到的数据文件夹……

至于生成的 Pyinstaller .exe 文件在 .pyc 文件尝试加载预期的 .DLL 时是否能正常工作,这就见仁见智了:-/

# Manually remove entire packages...

exclude = ["scipy", "IPython", "zmq"]
a.binaries = [x for x in a.binaries if not x[0].startswith(tuple(exclude))]

# Target remove specific ones...

a.binaries = a.binaries - TOC([
 ('sqlite3.dll', None, None),
 ('tcl85.dll', None, None),
 ('tk85.dll', None, None),
 ('_sqlite3', None, None),
 ('_ssl', None, None),
 ('_tkinter', None, None)])

# Add a single missing dll...

a.binaries = a.binaries + [
  ('opencv_ffmpeg245_64.dll', 'C:\\Python27\\opencv_ffmpeg245_64.dll', 'BINARY')]

# Delete everything bar matplotlib data...

a.datas = [x for x in a.datas if
 os.path.dirname(x[1]).startswith("C:\\Python27\\Lib\\site-packages\\matplotlib")]

撰写回答