PyInstaller快速上手教程
大约 4 分钟
PyInstaller
安装
pip install git+https://github.com/pyinstaller/pyinstaller
参数
参数 | 作用 | |
---|---|---|
-F 文件.py | 生成单一的exe文件,产生一个文件用于部署 | 常用 |
-w 文件.py | 使用Windows子系统执行.当程序启动的时候不会打开命令行,去掉控制台窗口,对于执行文件没有多大的用处,一般用于GUI界面使用,(只对Windows有效) | |
-i 图标路径 | 可执行文件的图标(只对Windows系统有效) | |
-D | 生成一个文件夹包括依赖文件,产生一个目录用于部署 (默认) | 常用 |
-p 搜索路径 | 添加Python使用的第三方库,添加必要的搜索路径,自定义需要加载的类路径,一般情况用不到 | |
-K | 在部署时包含 TCL/TK | |
-c | 使用控制台子系统执行,控制台无窗口(默认)(只对Windows有效) | |
--add-data "img;img" | 打包时包含非py文件的资源 |
图片打包的方法
可以把图像文件转换成py文件中的变量。py有这个工具,也可能是wxpy有。
可以把图像文件放到程序下的一个文件夹里,随程序分发。
放到exe里肯定也可以,你得写好setup文伴,确保把图像文件包含在内。
# 首先先打第一包
pyinstaller main.py
# 在当前目录下打开main.spec文件,将图片资源文件夹加载进来
a.datas += [('img','E:\\svnProject\\shenjidaili_project\\winProject\\img','DATA')]
# 再次使用spec文件打包
pyinstaller main.spec
如何将资源文件一起打包至exe中
神鸡代理软件打包示例
- 创建零食目录路径查找函数
- 将所有图片路径加上查找函数
#>>> vim utils.py
import sys
import os
import re
# 在 windows 下将程序打包成 exe 的库,会将一个变量 frozen 注入到 sys 中。可以用来确定当前运行的程序是脚本文件还是exe打包程序
# 生成资源文件目录访问路径
def resource_path(relative_path):
if getattr(sys, 'frozen', False): # 是否Bundle Resource
# base_path = os.path.dirname(os.path.abspath(sys.executable))
# base_path = os.path.dirname(sys.executable)
# os.chdir(base_path)
base_path = sys._MEIPASS
else:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
# 仅仅做为脚本函数,修改文件内容的图片路径
def switch_path(file_name):
regex_str = r'u*[\"\']img/.*?[\"\']'
pattern = re.compile(regex_str)
# 读取文件内容
f = open(file_name, 'r', encoding="utf-8")
alllines = f.readlines()
f.close()
# 匹配字符串
str_list = []
for eachline in alllines:
one_str_list = pattern.findall(eachline)
str_list += one_str_list
# 替换字符串并写入文件
f = open(file_name, 'w+', encoding="utf-8")
for eachline in alllines:
newline = None
for resource_str in str_list:
if eachline.find(resource_str) != -1:
newline = eachline.replace(resource_str, "resource_path(" + resource_str + ")")
# a = re.sub(resource_str, "resource_path("+ resource_str + ")", eachline)
break
if newline:
f.writelines(newline)
else:
f.writelines(eachline)
f.close()
# 插入一行
with open(file_name, 'r+', encoding="utf-8") as f:
content = f.read()
f.seek(0, 0)
f.write('from utils import resource_path\n')
if __name__ == "__main__":
switch_path("build_frame.py")
python utils.py
打包时加上
img
图片资源目录pyinstaller -i "favicon.ico" -F -w --add-data "img;img" main.py
# 调试模式 pyinstaller -i "favicon.ico" -F --add-data "img;img" main.py
https://www.cnblogs.com/darcymei/p/9397173.html
多进程打包
官方打包解释:https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing
新建自定义一个多进程模块(照写)
#>>> vim mul_process_package.py import os import sys import multiprocessing # Module multiprocessing is organized differently in Python 3.4+ try: # Python 3.4+ if sys.platform.startswith('win'): import multiprocessing.popen_spawn_win32 as forking else: import multiprocessing.popen_fork as forking except ImportError: import multiprocessing.forking as forking if sys.platform.startswith('win'): # First define a modified version of Popen. class _Popen(forking.Popen): def __init__(self, *args, **kw): if hasattr(sys, 'frozen'): # We have to set original _MEIPASS2 value from sys._MEIPASS # to get --onefile mode working. os.putenv('_MEIPASS2', sys._MEIPASS) try: super(_Popen, self).__init__(*args, **kw) finally: if hasattr(sys, 'frozen'): # On some platforms (e.g. AIX) 'os.unsetenv()' is not # available. In those cases we cannot delete the variable # but only set it to the empty string. The bootloader # can handle this case. if hasattr(os, 'unsetenv'): os.unsetenv('_MEIPASS2') else: os.putenv('_MEIPASS2', '') # Second override 'Popen' class with our modified version. forking.Popen = _Popen
修改程序进入文件
#>>> vim main.py import mul_process_package # 导入刚建的模块 import multiprocessing if __name__ == '__main__': # 这个重要,必须要加 multiprocessing.freeze_support()
如果要在windows下使用multiprocessing,必须在代码入口添加multiprocessing.freeze_support( ),否则用pyinstaller打包成exe,执行中会出现主进程无限循环的问题。
subprocess模块失效问题
使用pyinstaller将python程序打包,不使用-w参数时(如“pyinstaller -F main.py -i cat.ico”)程序运行正常,但使用-w参数去掉console控制台后,程序便卡在了一个地方无法继续运行,经过调试发现,出问题的地方在subprocess.Popen语句。
错误代码示范
popen = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
正确代码示范
# 添加stdin=subprocess.PIPE参数
popen = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 当去掉终端窗口时,程序没有等待命令执行结果就退出了,所以添加等待就可以了
popen.wait()
#
popen.stdout.close()
popen.stderr.close()
stdin=subprocess.PIPE
参数是一定要有。
shell=Ture
:不会弹出console;shell=False
:会弹出一个console
其他解决办法(未尝试过)
# 在创建进程时,加上startupinfo参数
si = subprocess.STARTUPINFO()
si.dwFlags|=subprocess.STARTF_USESHOWWINDOW
mProcess=subprocess.Popen(cmd,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,startupinfo=si)