总结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中zip()函数用法实例教程
Jul 31 Python
Python中replace方法实例分析
Aug 20 Python
Python实现股市信息下载的方法
Jun 15 Python
详解Django通用视图中的函数包装
Jul 21 Python
谈谈如何手动释放Python的内存
Dec 17 Python
Python可变参数用法实例分析
Apr 02 Python
解决phantomjs截图失败,phantom.exit位置的问题
May 17 Python
Django框架的中的setting.py文件说明详解
Oct 15 Python
Django 框架模型操作入门教程
Nov 05 Python
python 实现全球IP归属地查询工具
Dec 18 Python
python基础入门之字典和集合
Jun 13 Python
详解Python如何批量采集京东商品数据流程
Jan 22 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中的正规表达式(二)
2006/10/09 PHP
PHP+SQL 注入攻击的技术实现以及预防办法
2011/01/27 PHP
php堆排序(heapsort)练习
2013/11/13 PHP
php从memcache读取数据再批量写入mysql的方法
2014/12/29 PHP
use jscript Create a SQL Server database
2007/06/16 Javascript
javascript multibox 全选
2009/03/22 Javascript
javascript轻松实现当鼠标移开时已弹出子菜单自动消失
2013/12/29 Javascript
JavaScript从数组中删除指定值元素的方法
2015/03/18 Javascript
jquery插件jquery.beforeafter.js实现左右拖拽分隔条对比图片的方法
2015/08/07 Javascript
js HTML5 Ajax实现文件上传进度条功能
2016/02/13 Javascript
浅析Bootstrap缩略图组件与警示框组件
2016/04/29 Javascript
Javascript将JSON日期格式化
2016/08/23 Javascript
详解Angular.js指令中scope类型的几种特殊情况
2017/02/21 Javascript
JavaScript比较同一天的时间大小实例代码
2018/02/09 Javascript
Vuex的基本概念、项目搭建以及入坑点
2018/11/04 Javascript
初学vue出现空格警告的原因及其解决方案
2019/10/31 Javascript
[00:43]DOTA2小紫本全民票选福利PA至宝全方位展示
2014/11/25 DOTA
python中的内置函数getattr()介绍及示例
2014/07/20 Python
Django日志模块logging的配置详解
2017/02/14 Python
Python对excel文档的操作方法详解
2018/12/10 Python
python实现简单五子棋游戏
2019/06/18 Python
Python 私有化操作实例分析
2019/11/21 Python
Python如何用filter函数筛选数据
2020/03/05 Python
Python中格式化字符串的四种实现
2020/05/26 Python
什么是Python中的匿名函数
2020/06/02 Python
Django REST Framework 分页(Pagination)详解
2020/11/30 Python
Python 带星号(* 或 **)的函数参数详解
2021/02/23 Python
Html+Css+Jquery实现左侧滑动拉伸导航菜单栏的示例代码
2020/03/17 HTML / CSS
美国最大的网上冲印店:Shutterfly
2017/01/01 全球购物
英国领先的男士服装和时尚零售商:Burton
2017/01/09 全球购物
STP的判定过程
2012/10/01 面试题
社区母亲节活动记录
2014/03/06 职场文书
大学生上课迟到检讨书
2014/10/15 职场文书
现役军人家属慰问信
2015/03/24 职场文书
《詹天佑》教学反思
2016/02/20 职场文书
pytorch 中autograd.grad()函数的用法说明
2021/05/12 Python