【Python】 如何用pyinstaller打包python程序成exe

时间:2022-05-23 17:52:50

【pyinstaller】

  pyinstaller在他们的官方网站上下载:http://www.pyinstaller.org/

  下载完pyinstaller之后还要安装一个支持包pywin32. 这个包允许了python访问windows系统的一些API,如果没有就会在编译过程中报错。

  当然,也可以用pip install pyinstaller来一站式下载pyinstaller和它的支持包。

  ■  打包步骤

  用cmd键入python ${pyinstaller根目录}/pyinstaller.py [参数] 入口文件.py即可。入口文件是指当你要打包多个文件为一个exe时的那个程序的入口文件。总之只要你的脚本在IDE或者cmd下是跑得通的那么久可以用pyinstaller来打包成exe。完成后的exe文件在pyinstaller目录中有一个和入口文件名同名的新目录,在这个目录的dist目录里躺着。

  参数可选:

    --console  在打包成exe后双击打开时会带出控制台来显示信息

    --windowed  与console相反,在双击打开exe后没有控制台

    --onefile  默认生成的是一个exe作为入口的一大堆文件,用这个参数把这一对文件さらに打包成一个exe,缺点是这个exe往往有点大。。

    --icon='path'  为生成的exe配一个图标,若不指定则用pyinstaller的默认图标

    等等.......

  *当打开exe秒退,却不知道为什么的时候,可以重新用--console参数再编译一遍,这样就可以看控制台里输出的错误信息了。

  更多参数:(引用自http://www.cnblogs.com/chjbbs/archive/2014/01/25/3533187.html):

  【Python】 如何用pyinstaller打包python程序成exe

■  pyinstaller的一些坑

  * 我用pyinstaller的几个项目全都是用wxpython写的GUI界面项目,然而有好几次,打包完之后总是会有各种各样的错误导致exe闪退。看了下报错信息发现错误行全部是在文件最上面的import部分。后来发现错误原因似乎是在import的时候不能用from wx import *这种形式。至于其他模块怎么样不是很清楚が,知道的一点是自己写的那些脚本当做第三方模块使用的时候用这种形式是ok的,而碰到wx的时候一定要老老实实import wx然后用wx.Frame之类的方式。。

  * 有几个程序有登录服务器的界面,我就加了一个同目录下生成配置文件,每次登录界面出现前读取配置文件,来加载上一次成功登录时的账密等信息。但是好几次在IDE里测试的时候OK的,变成exe之后就不行了。后来发现,原来是脚本的属性__file__的锅。在exe中,似乎是不会解释__file__的,所以导致没有办法读取到当前exe的文件路径。

■  部分环境依赖强的程序打包时碰到各种破问题的解决

  将一些工具从字符界面或者GUI的形式转化为WEB表现形式似乎是一种很好的选择。然而WEB编程的时候必然会碰到各种各样的目录/相对路径等等问题。在打包的时候显得特别难受。

  这么说吧,打包成一个exe双击打开之后,其os.path.abspath(__file__)默认是一个建在用户文件夹中的一个临时目录而不是当前程序所在目录或者cmd中所在目录(即使你是在这个目录下运行的程序)。这么一来就使得程序中写相对路径找文件肯定是不行的。可以理解成系统将要执行的exe复制到了一个临时目录,但是又没有复制原来exe所在目录下的其他一些文件,导致找不到文件的错误发生。这样,所有基于__file__的文件补充写法都会变得无效了 。

  另一种补充文件路径的写法是os.getcwd()。这个返回的是工作目录,所以只要在工作目录下打开exe程序(这也是一般双击打开exe程序的一般做法),就可以在相关目录下找到相关的文件。在每一个相对路径前面加上os.getcwd的话虽然比较繁琐但是可以比较稳地指出所有想要使用的文件的绝对路径。

  其实更加方便的一种方法就是在一切代码开始之前就执行以下os.system('cd %s' % os.path.abspath()),把相对目录的路径调整到想要到的工作目录下,这样后面的相对路径写成的文件名就不用改了。

  再补充一下关于flask的,因为上面说的web化GUI或者字符工具我就是用flask做的。flask在寻找templates、static等自带的项目目录下的文件夹时并不是简单地搜寻工作目录,而是有一套自己的方法。在不修改源码的前提下,可以考虑flask.Flask()方法加上参数template_folder和static_folder两个=os.path.join(os.getcwd(),'templates'),os.path.join(os.getcwd(),'static')这样的方法来做。还有一个常用的扩展是flask_bootstrap,继承其模板时也会报错,我没有去看源码看它到底是如何寻找模板文件的,而是直接把base.html复制到本项目目录下然后让本项目的模板文件继承。。

■  字符问题

  除了上面说到的不能import * 以及相对路径起点不能用os.path.dirname(os.path.abspath(__file__))而用os.getcwd()以外,还有一点就是编码的问题。我们脚本中总是习惯性的声明coding:utf-8,这就导致所有的中文字符都是以utf-8形式编码。而包装秤exe之后在dos中运行,通常shell的默认编码是gbk。所以开发时可以保持coding:utf-8,但是用pyinstaller封装前最好改成coding:gbk,以防止控制台乱码的出现。