总结Pyinstaller打包的高级用法


Posted in Python onJune 28, 2021

一、安装pyinstaller

PyInstaller是一个用来将Python程序打包成一个独立可执行文件的第三方包。

因是第三方包,所以需要安装一下:

pip install pyinstaller

或者升级到最新版本:

pip install --upgrade pyinstaller

或者安装开发者版本:

pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz

当然了,也可以下载whl文件,然后pip install安装

更多可参考官网指引:

http://www.pyinstaller.org/downloads.html

二、打包初体验

我们简单试下打包python代码为exe可执行文件,测试代码如下:

# 测试.py
import os

path = os.getcwd()
print(f'当前文件路径:{path}')
os.system('pause')

这段代码是打印文件所在的目录,我们用pyinstaller简单打包的命令如下:

pyinstaller -F 测试.py

这个命令,执行过程如下:

(env_test) F:\PythonCool\pyinstaller>pyinstaller -F 测试.py    
403 INFO: PyInstaller: 4.3
403 INFO: Python: 3.8.10 (conda)
434 INFO: Platform: Windows-10-10.0.19042-SP0
436 INFO: wrote F:\PythonCool\pyinstaller\测试.spec
455 INFO: UPX is not available.
468 INFO: Extending PYTHONPATH with paths
['F:\\PythonCool\\pyinstaller', 'F:\\PythonCool\\pyinstaller']
501 INFO: checking Analysis
...
...
15006 INFO: Appending archive to EXE F:\PythonCool\pyinstaller\dist\测试.exe
18999 INFO: Building EXE from EXE-00.toc completed successfully.

成功后会在同级目录下生成一个dist文件,里面就是一个和代码文件名同名的可执行文件:

总结Pyinstaller打包的高级用法

双击该可执行文件,我们可以看到直接在python解释器里运行测试.py文件时一样的结果:

总结Pyinstaller打包的高级用法

这里需要注意的是,我们在进行打包的时候,有必要指定被打包的py文件的路径,两种方式供选择:

方式一:先切换到被打包py文件目录,再执行打包指令

(base) C:\Users\Gdc>cd F:\PythonCool\pyinstaller
(base) C:\Users\Gdc>F:
(base) F:\PythonCool\pyinstaller>pyinstaller -F 测试.py

方式二:打包指令中指定py文件的绝对路径

(base) C:\Users\Gdc>pyinstaller -F F:\PythonCool\pyinstaller\测试.py

关于成功打包的测试.exe可执行文件,我们发现其图标是默认的,且启动时会显示命令行窗口。那么,我们可以怎么自定义exe图标,又或者去掉命令行窗口呢?

三、打包进阶体验

好了,接下来,我们先看看关于pyinstaller打包时候的一些别的参数都有哪些,如何自定义exe图标以及如何去掉命令行窗口等等。

(env_test) F:\PythonCool\pyinstaller>pyinstaller -h

pyinstaller -h可以查看其参数说明,由于较多这里不做完整展示,摘取部分常用参数做简要介绍:

参数 说明
-F 产生单个的可执行文件
-D 产生一个目录(包含多个文件)作为可执行程序
-a 不包含 Unicode 字符集支持
-d debug 版本的可执行文件
-w 指定程序运行时不显示命令行窗口(仅对 Windows 有效)
-c 指定使用命令行窗口运行程序(仅对 Windows 有效)
-o 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件
-p 设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径
-n 指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字

打包一个带自定义icon的exe可执行文件

我们可以去这里下载icon文件:

https://www.iconfont.cn/

可以去这里将图片转化为icon文件:

https://www.bitbug.net/

然后,用一下命令可以自定义exe图标:

(env_test) F:\PythonCool\pyinstaller>pyinstaller -F -i icon.ico 测试.py

成功后,我们可以看到图标变成了我们自定义的这个:

总结Pyinstaller打包的高级用法

打包去掉命令行弹窗的exe可执行文件

如果我们是有GUI的程序,想在启动的时候去掉命令行窗口,那么可以用以下指令进行打包,这里以tkinter内置GUI库为例展示:

# 测试.py
import tkinter

top = tkinter.Tk()
# 进入消息循环
top.mainloop()

以上测试代码,如果用初体验中的方式,在GUI界面出现的同时也会出现命令行弹窗,我们想去掉命令行弹窗可以:

(env_test) F:\PythonCool\pyinstaller>pyinstaller -F -w -i icon.ico 测试.py

双击打包后的exe文件,可以看到只会出现GUI界面,命令行窗口并没有出现。

总结Pyinstaller打包的高级用法

四、带配置文件打包

所谓带配置文件打包,这里是指打包的时候除了py文件、依赖的库之外,还存在需要引用的其他资源文件。直接用以上方式打包的时候,这些资源是无法被打进包的,我们需要进行修改打包时的spec文件来实现。

spec文件是告诉Pyinstaller怎么打包py文件,比如路径、资源、动态库、隐式调用的模块等等。一般来说,我们不需要对它进行修改…

这里我用此前《词云绘制小工具》的案例来进行介绍。

我们直接用打包进阶体验中的命令可以进行成功打包,不过这里我们发现有两个问题:①包体很大,比此前案例里大了10倍左右;②启动exe文件的时候报错了。

总结Pyinstaller打包的高级用法

关于包体较大的情况,可以试着创建虚拟环境,然后只安装程序里需要调用的库即可,这里只简单介绍:

# 创建虚拟环境
conda create -n your_env_name python=3.8.10
# 启动虚拟环境
activate your_env_name

关于启动报错的情况,由于比较复杂,我们一步一步来看:

①由于无命令行弹窗,无法查看到具体的报错,这里先去带命令行窗口形式看下报错信息,我们看报错如下:

总结Pyinstaller打包的高级用法

提示缺少这个文件,我们可以在打包生成的词云绘制工具.spec配置文件里将这个资源放上

# -*- mode: python ; coding: utf-8 -*-
# 词云绘制工具.spec

block_cipher = None

a = Analysis(['词云绘制工具.py'],
             pathex=['F:\\PythonCool\\pyinstaller'],
             binaries=[],
             datas=[], # 这里带上资源文件地址
             hiddenimports=[], # 动态引入的库或模块
             hookspath=[],
             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='词云绘制工具',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True , icon='icon.ico')

通过在wordcloud模块目录里查到了stopwords文件,我们将其放到data中。

总结Pyinstaller打包的高级用法

datas=[('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\wordcloud\\stopwords','wordcloud')],

前者是资源文件在本机的位置,后者为打包后文件调用的相对路径,编辑好spec文件后,通过以下命令进行打包:

(env_test) F:\PythonCool\pyinstaller>pyinstaller -D 词云绘制工具.spec

总结Pyinstaller打包的高级用法

好吧,还有一些文件未被打进包,所以又出现同样的问题了。所以,我们是需要把全部的资源文件都加到spec文件里的data中。

我们找到全部的资源文件全部加上吧,然后再执行打包命令。

datas=[('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\stylecloud\\static','stylecloud\\static'),
    ('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\wordcloud\\stopwords','wordcloud'),
    ('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\jieba\\analyse\\idf.txt','jieba\\analyse'),
    ('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\jieba\\dict.txt','jieba')]

我们将配置资源打进包后可以正常启动exe可执行文件了。

总结Pyinstaller打包的高级用法

但是,又发现在执行词云绘制的时候,也会出现报错。不过看报错的情况是提示不存在xx模块,那么这是什么情况呢?!

五、添加隐式调用库

我们找到报错的地方代码如下,采用了__import__()函数用于动态加载类和函数palettable模块。

def gen_palette(palette: str):
    """Generates the corresponding palette function from `palettable`."""
    palette_split = palette.split(".")
    palette_name = palette_split[-1]

    # https://stackoverflow.com/a/6677505
    palette_func = getattr(
        __import__(
            "palettable.{}".format(".".join(palette_split[:-1])),
            fromlist=[palette_name],
        ),
        palette_name,
    )
    return palette_func

对于这个问题,我试过两种方案,大家可以参考一下。

方案一:在spec文件中hiddenimports中添加动态引用的模块

hiddenimports=['palettable'], # 动态引入的库或模块

这种情况下,palettable库里也有一些配置文件需要添加到spec文件里的data中

('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\palettable\\colorbrewer\\data','palettable\\colorbrewer\\data')

方案二:修改stylecloud库中调用palettable模块的代码部分

import palettable
def gen_palette(palette: str):
    palette_func = getattr(palettable.tableau,'BlueRed_6')
    return palette_func
 
    # """Generates the corresponding palette function from `palettable`."""
    # palette_split = palette.split(".")
    # palette_name = palette_split[-1]

    #    https://stackoverflow.com/a/6677505
    # palette_func = getattr(
        # __import__(
            # "palettable.{}".format(".".join(palette_split[:-1])),
            # fromlist=[palette_name],
        # ),
        # palette_name,
    # )

通过第4和5部分,我们用pyinstaller终于成功打包且正常运行使用了。

总结Pyinstaller打包的高级用法

以上就是本次全部内容,大家如果遇到打包时涉及到配置文件的或者隐式调用的,可以采用这两个2技巧进行特殊打包!

不过,关于pyinstaller打包其实还有更多操作,大家可以多看看官方文档了解,主要是命令行参数spec文件里的配置要点

到此这篇关于总结Pyinstaller打包的高级用法的文章就介绍到这了,更多相关Pyinstaller打包内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python enumerate遍历数组示例应用
Sep 06 Python
Python解析json之ValueError: Expecting property name enclosed in double quotes: line 1 column 2(char 1)
Jul 06 Python
Python + selenium自动化环境搭建的完整步骤
May 19 Python
Python实现读取SQLServer数据并插入到MongoDB数据库的方法示例
Jun 09 Python
python实现zabbix发送短信脚本
Sep 17 Python
python增加图像对比度的方法
Jul 12 Python
解决Tensorflow 内存泄露问题
Feb 05 Python
Python 基于FIR实现Hilbert滤波器求信号包络详解
Feb 26 Python
Python数据相关系数矩阵和热力图轻松实现教程
Jun 16 Python
python向xls写入数据(包括合并,边框,对齐,列宽)
Feb 02 Python
写一个Python脚本下载哔哩哔哩舞蹈区的所有视频
May 31 Python
健身房被搭讪?用python写了个小米计时器助人为乐
Jun 08 Python
Pandas数据类型之category的用法
Jun 28 #Python
Python爬虫框架之Scrapy中Spider的用法
Jun 28 #Python
简单谈谈Python面向对象的相关知识
Jun 28 #Python
Python利用机器学习算法实现垃圾邮件的识别
浅谈Python中的正则表达式
Jun 28 #Python
python中subplot大小的设置步骤
手把手教你实现PyTorch的MNIST数据集
You might like
利用php抓取蜘蛛爬虫痕迹的示例代码
2016/09/30 PHP
PHP通过引用传递参数用法分析
2016/12/01 PHP
雄兵连第三季海报曝光,艾妮熙德成主角,蔷薇新造型
2021/03/09 国漫
小试JQuery的AutoComplete插件
2011/05/04 Javascript
jQuery使用post方法提交数据实例
2015/03/25 Javascript
jquery实现网页的页面平滑滚动效果代码
2015/11/02 Javascript
BootStrap 智能表单实战系列(五) 表单依赖插件处理
2016/06/13 Javascript
easyui datebox 时间限制,datebox开始时间限制结束时间,datebox截止日期比起始日期大的实现代码
2017/01/12 Javascript
防止重复发送 Ajax 请求
2017/02/15 Javascript
Bootstrap模态框(Modal)实现过渡效果
2017/03/17 Javascript
Javascript格式化并高亮xml字符串的方法及注意事项
2018/08/13 Javascript
vue 实现搜索的结果页面支持全选与取消全选功能
2019/05/10 Javascript
taro小程序添加骨架屏的实现代码
2019/11/15 Javascript
jQuery实现可编辑的表格
2019/12/11 jQuery
js实现旋转木马轮播图效果
2020/01/10 Javascript
vue+Element-ui前端实现分页效果
2020/11/15 Javascript
微信小程序实现简单购物车功能
2020/12/30 Javascript
[03:09]显微镜下的DOTA2第一期——带你走进华丽的DOTA2世界
2014/06/20 DOTA
Python获取脚本所在目录的正确方法
2014/04/15 Python
Python求两个list的差集、交集与并集的方法
2014/11/01 Python
python通过floor函数舍弃小数位的方法
2015/03/17 Python
自己编程中遇到的Python错误和解决方法汇总整理
2015/06/03 Python
python使用scrapy发送post请求的坑
2018/09/04 Python
win10系统下python3安装及pip换源和使用教程
2020/01/06 Python
pytorch 实现在预训练模型的 input上增减通道
2020/01/06 Python
Python实现栈的方法详解【基于数组和单链表两种方法】
2020/02/22 Python
Forever 21美国官网:美国标志性快时尚品牌
2017/02/20 全球购物
应届生如何写自荐信
2014/01/05 职场文书
实习生评语
2014/04/26 职场文书
质量标语大全
2014/06/12 职场文书
毕业生班级鉴定评语
2015/01/04 职场文书
工作简历自我评价
2015/03/11 职场文书
红色经典观后感
2015/06/18 职场文书
使用 CSS 轻松实现一些高频出现的奇形怪状按钮
2021/12/06 HTML / CSS
详细介绍Next.js脚手架完整搭建封装
2022/04/26 Javascript
CSS控制继承中的height能变为可继承吗
2022/06/10 HTML / CSS