【python】使用pyinstaller打包python程序为exe【转】

发布时间 2023-05-21 18:08:26作者: 老年新手工程师

pyinstaller

介绍

PyInstaller除了win32平台外还支持Linux,Unix平台.py2exe的用法在前面的博文里已经有了,现在看看PyInstaller,pyinstaller是目前应用最多的python打包工具,也是我最常用的。

PyInstaller本身并不是Python模块,所以安装时随便放在哪儿都行。

优点:

  1. 可将python文件转成可执行文件
  2. 跨平台
  3. 输出的可以是单一目录,也可以是一个单独的打好包的可执行文件。py2exe貌似输出目录。
  4. 智能支持python的第三方模块如PyQt,外部数据文件等
  5. 支持EGG格式文件
  6. 可执行文件可以用UPX压缩,二进制压缩方式
  7. 支持控制台和视窗两种方式。
  8. 可以选择exe文件的图标 (Windows only)
  9. 支持 COM server (Windows only)

缺点:

  1. import导入的问题

pyinstaller是很智能的,只要指定了入口py文件,那么它就会根据代码自动查找需要导入的包。但是隐式导入的话,平常运行是没有问题的,举例:

# test1.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker


DB_CONNECT_STRING = 'mysql+pymysql://root:123456@localhost/study'
engine = create_engine(DB_CONNECT_STRING, echo = False)
DB_Session = sessionmaker(bind = engine)
session = DB_Session()

print('this is my test')

运行这个ORM库的初始化引擎,是没有问题的,在console得到结果:

this is my test

那么我们开始打包,使用最简单的pyinstaller test1.py。打包完成后,在当前目录下有个dist文件夹,进入dist下的test1文件夹,然后打开cmd,运行这个exe,我们就会发现:

提示: no model named 'pymysql'

这是怎么回事呢?那么问题来了,sqlalchemy这个库在初始化的时候是不需要显示导入引擎库的,它自己有一个create_engine()的函数来初始化,这个字符串是使用者根据规则来自己填写的。其实解决的方法很简单,我们只要在显式导入pymysql这个库即可。现在我们导入这个库:

import pymysql

重新打包一遍(重新打包的时候记得删除掉spec文件,否则会有缓存,或者是加上--clean选项清除掉),再次运行,现在就没有这个问题了。

  1. 多进程打包的问题

官方的CPython存在一个GIL锁,这个锁的存在有很多优点,很多库都是线程安全的,单线程执行的效率也高。在python早期的一个版本中取消掉了GIL,代之以高粒度的锁来实现多线程,但是实际应用中单个线程的效率大大降低。故后来又将GIL这个锁还原回去,所以至今的python2也好还是python3中都会有这个锁。但是这个锁有很大一个问题,那就是效率问题,它导致了python仅仅只能利用一个core来进行数据的计算。所以后面为了弥补这个GIL带来的问题,专家们设计了multiprocessing库,gevent库等。前一个是多进程库,为了解决python用于数据密集型处理的情况;后一个用于异步IO处理的情况,基本原理就是在CPU时钟之间来回切换,简单的例子就是爬虫程序爬取网页的时候。假如有10个url,我们都要去GET它,实际上网络之间的延迟是大大高于计算机内部的,那么这个时间内计算机就切换到下一个。

有时候运用多进程是必须的,这个替代不了,哪怕它占用资源很多。

使用

  1. 首先安装

一般情况下:

pip install pyinstaller

但是会爆错误,比如命令行下出现

UnicodeDecodeError: 'gbk' codec can't decode pyinstaller等等

这个时候下载pyinstall按转包文件解压后,放在没有中文的目录下,输入

python setup.py install

即可完成

  1. 首先写一个main.py的文件,到网上下载一个图标,保存为logo.ico

使用方法(例子)在:

pyinstaller -D -p F:\Python27\Lib -i logo.ico mian.py

-D:打包成多个文件
-p:指定python安装包路径
-i:指定图标,到网上下载一个图标,保存为logi.ico文件,
mian.py:要打包的文件
注意main.py与logo.ico必须放在同一个目录下
-D与-F一一对应,-F是打包成一个单独的文件。
最后一排加上--noconsole,就是无窗口运行。

运行完命令行即可生成exe文件

多进程打包

如果py程序是多进程的话,使用pyinstaller打包会出现错误,这个时候只要加上一行代码

在:

    if __name__=='__mian__':
        #新增下面一行代码即可打包多进程
        multiprocessing.freeze_support()  

word文件打包

如果要打包那种操作word的文件代码,用pyinstaller工具把使用到python-docx库的脚本打包成exe可执行文件后,双击运行生成的exe文件,报错:

docx.opc.exceptions.PackageNotFoundError: Package not found at 'C:\Users\ADMINI~1.PC-\AppData\Local\Temp\_MEI49~1\docx\templates\default.docx'

经过在stackoverflow上搜索,发现有人遇到过类似的问题(问题链接:cx_freeze and docx - problems when freezing),经过尝试,该问题的第二个回答可以解决这个问题:

I had the same problem and managed to get around it by doing the following. First, I located the default.docx file in the site-packages. Then, I copied it in the same directory as my .py file. I also start the .docx file with Document() which has a docx=... flag, to which I assigned the value: os.path.join(os.getcwd(), 'default.docx') and now it looks like doc = Document(docx=os.path.join(os.getcwd(), 'default.docx')). The final step was to include the file in the freezing process. Et voilà! So far I have no problem.

大概的解决步骤是这样的:

找到python-docx包安装路径下的一个名为default.docx的文件,我是通过everything这个强大的搜索工具全局搜索找到这个文件的,它在我本地所在的路径是:

E:\code\env\.env\Lib\site-packages\docx\templates

把找到的default.docx文件复制到我的py脚本文件所在的目录下。
修改脚本中创建Document对象的方式:
从原来的创建方式:

document = Document()

修改为:

import os
document = Document(docx=os.path.join(os.getcwd(), 'default.docx'))

再次用pyinstaller工具打包脚本为exe文件

把default.docx文件复制到与生成的exe文件相同的路径下,再次运行exe文件,顺利运行通过,没有再出现之前的报错,问题得到解决。

其他事项

有的时候你打包图标的时候会报错,会显示logo error之类的,这是因为图标里面的格式出错了,需要用图片编辑软件重新对图片内部大小进行设置,这个百度一下吧~

如果要加密混淆代码(其实没有用,一样可以反编译出你的源代码,但是聊胜于无吧)

加上一行 --key=asfweakjhfksafkasdkdbas随便几个字符串

好像要安装依赖包,根据提示安装即可

 

转发自 https://zhuanlan.zhihu.com/p/355304094#:~:text=%E7%9B%AE%E5%89%8D%E5%AF%B9pytho,%E5%92%8C%E6%8F%90%E4%BE%9B%E6%96%B0%E7%9A%84%E5%8A%9E%E6%B3%95%E3%80%82