pyinstaller - 将Python脚本打包成EXE

将Python脚本打包成可执行文件,以EXE形式执行Python脚本。

pyinstaller - 将Python脚本打包成EXE

1 pyinstaller

1.1 pyinstaller简介

pyinstaller同时支持python2.7和python3.3/3.4/3.5多个版本。

pyinstaller工作原理:

PyInstaller reads a Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files – including the active Python interpreter! – and puts them with your script in a single folder, or optionally in a single executable file.

Pyinstaller实现的是 打包(bundle) Python脚本及其依赖项,包括Python解释器,使其能在未安装Python的环境中运行。

  • 注意:不是编译(compile),是打包(bundle)!
    • pyinstaller打包后的EXE可执行文件,是有一个类似bootloader的文件,这个bootloader文件去加载启动该EXE包中的Python解释器,然后由这个解释器去解释Python脚本、处理动态链接库等Python运行的事情。
    • 由于pyinstaller所做的实际上并不是将脚本文件做编译处理。pyinstaller只是连带解释器、依赖文件、链接库等资源打包。因此,pyinstaller生成的EXE可执行文件没有改变Python解释型语言的本质,也不会在运行速度上带来解释型到编译型的提升。充其量在链接、加载阶段,打包处理后的文件可能会因资源检索、IO传输量的减少,而缩短时间。但运行阶段不会有本质变化。
    • pyinstaller实际上是用于实现在未安装Python的环境下运行Python脚本。

pyinstaller.org

1.2 安装

1
pip install pyinstaller

1.3 使用

1
pyinstaller -F demo.py
  • -F 选项表示打包成一个独立的可执行文件
  • 打包完成后,可执行文件会出现在当前目录下的dist目录中。
    • 注意不是build目录

详细信息参考:

Using PyInstaller - Pyinstaller Docs


2 pyinstaller处理requests包的问题

2.1 情况

我的SudaLogin.py脚本中,处理网络编程的部分使用了requests包,经测试,pyinstaller在处理requests包时,生成的EXE无法正确执行。

执行时会报错:

  • No module named 'queue'
  • No module named 'urllib3'

urllib3通过pip安装一个即可消除报错。问题是queue。

2.2 分析

我在stackoverflow上查到了相关讨论:

PyInstaller doesn't import Queue - stackoverflow

摘选:

I don't think this is a PyInstaller or Twisted related issue at all. The Queue module is part of the standard library, and the issue is how you're naming it. In Python 2, it's Queue with a capital letter, but in Python 3, it's renamed queue to follow the more standard naming convention where modules have lowercase names.

Your script seems like it's a port of Python 2 code to Python 3 (thus the as Queue part of the import), but you're running it with Python 2 still. That may fail in other more subtle ways than just the Queue import being wrong (e.g. its Unicode handling may be all wrong).

  • 结合报错信息,就是说urllib3/packages/six.py中使用了的queue包在Python历史上有两个命名,Python2时代的Queue和Python3时代的queue。命名上的变迁导致pyinstaller无法确切地解析queue包。

更详细的讨论:

Needed modules are not collected on windows becasue of names with different case are treated the same #1935 - GitHub

2.3 解决

解决方法:

  • 使用--hidden-import选项即可

经测试,打包时,输入:

1
pyinstaller -F --hidden-import=queue SudaLogin.py
  • 此后输出的可执行程序可以正常运行了!