总结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 相关文章推荐
Python3基础之list列表实例解析
Aug 13 Python
Python的设计模式编程入门指南
Apr 02 Python
在IIS服务器上以CGI方式运行Python脚本的教程
Apr 25 Python
python实现复制整个目录的方法
May 12 Python
微信跳一跳自动运行python脚本
Jan 08 Python
TensorFlow实现卷积神经网络CNN
Mar 09 Python
python中将\\uxxxx转换为Unicode字符串的方法
Sep 06 Python
python执行精确的小数计算方法
Jan 21 Python
python同时替换多个字符串方法示例
Sep 17 Python
Python如何使用bokeh包和geojson数据绘制地图
Mar 21 Python
Python接口测试数据库封装实现原理
May 09 Python
python利用appium实现手机APP自动化的示例
Jan 26 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
神族 Protoss 历史背景
2020/03/14 星际争霸
php结合飞信 免费天气预报短信
2009/05/07 PHP
php下将图片以二进制存入mysql数据库中并显示的实现代码
2010/05/27 PHP
php 批量替换html标签的实例代码
2013/11/26 PHP
thinkphp3.2实现上传图片的控制器方法
2016/04/28 PHP
php生成二维码图片方法汇总
2016/12/17 PHP
Laravel框架Blade模板简介及模板继承用法分析
2019/12/03 PHP
jquery 将disabled的元素置为enabled的三种方法
2009/07/25 Javascript
jquery向.ashx文件post中文乱码问题的解决方法
2011/03/28 Javascript
js字符串的各种格式的转换 ToString,Format
2011/08/08 Javascript
javascript中的self和this用法小结
2014/02/08 Javascript
js时间比较示例分享(日期比较)
2014/03/05 Javascript
关于Javascript加载执行优化的研究报告
2014/12/16 Javascript
js日期插件dateHelp获取本月、三个月、今年的日期
2016/03/07 Javascript
js继承实现方法详解
2016/12/16 Javascript
详解Vue2.0里过滤器容易踩到的坑
2017/06/01 Javascript
js 获取元素的具体样式信息getcss(实例讲解)
2017/07/05 Javascript
原生JS获取元素的位置与尺寸实现方法
2017/10/18 Javascript
vue.js打包之后可能会遇到的坑!
2018/06/03 Javascript
你不知道的Vue技巧之--开发一个可以通过方法调用的组件(推荐)
2019/04/15 Javascript
[01:02]2014 DOTA2国际邀请赛中国区预选赛 现场抢先看
2014/05/22 DOTA
python十进制和二进制的转换方法(含浮点数)
2018/07/07 Python
Django 日志配置按日期滚动的方法
2019/01/31 Python
Python如何计算语句执行时间
2019/11/22 Python
opencv之为图像添加边界的方法示例
2019/12/26 Python
Python ArgumentParse的subparser用法说明
2020/04/20 Python
pytorch 中forward 的用法与解释说明
2021/02/26 Python
小程序瀑布流解决左右两边高度差距过大的问题
2019/02/20 HTML / CSS
T3官网:头发造型工具
2019/12/26 全球购物
英国发展最快的在线超市之一:Click Marketplace
2021/02/15 全球购物
会计自我鉴定范文
2013/10/06 职场文书
科技开发中心办公室主任岗位责任制
2014/02/10 职场文书
青年文明号口号
2014/06/17 职场文书
向女朋友道歉的话
2015/01/20 职场文书
销售督导岗位职责
2015/04/10 职场文书
信息简报范文
2015/07/21 职场文书