暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

用pyinstaller把python脚本打包成二进制文件

乔克的好奇心 2019-06-21
2863

最近在写一些python脚本,由于涉及很多pip库,再加上内网无法直接访问互联网,所以安装起来很麻烦。所以就想到怎么把脚本打包成二进制文件,相同的环境的情况下就可以解决装包这个麻烦事。在这个过程中也是踩了很多坑,最后还是在大佬的点拨下完成了,在这里记录总结下分享给大家,希望对大家有用。

前言

在编写python脚本的时候,有时候我们会需要很多依赖库,如果只是脚本,在别的机器上运行就也需要安装这些依赖库,这是一个非常麻烦的时候,解决这个问题的思路有以下几种:
(1)、用docker,在docker里解决这些依赖,然后封装成镜像,这样就可以在各种机器上运行了;
(2)、使用virtualenv进行本地包安装,然后把安装好的文件拷贝到服务器上;
(3)、把包打成二进制文件;

由于我们内部业务没用docker,所以第一点就排除了,至于第二点还是比较麻烦,直接舍弃。妥妥的研究第三种了。
在用pyinstaller的时候踩了几个坑:
(1)、你原始主机(准备用来打包)的主机,如果环境比较混乱,比如有pyhton2也有python3,在用pyinstaller的时候会出现一些莫名奇妙的错误(就是打出来的包用不了),我在这个坑里躺了很久;
(2)、如果你在centos7上打的包,跑到centos6上运行脚本,会报一些openssl、glibc等版本太低的问题,这种情况下,你在centos7上打的包就只能在centos7上跑,要在6上跑,只能用centos6的服务器打包;

强烈建议:最好在什么环境下打的包就在相同的环境下跑。比如我系统版本是CentOS7.5,python版本是2.7.5,那我在这个上面打的包就在这类型的机器上跑这个脚本,基本是没问题的。

一、安装

1、安装pip(可选)

看你服务器上是否有pip,如果没有,需要安装,安装方法如下:

  1. # 通过yum来安装

  2. yum install -y epel-release

  3. yum install -y python-pip


  4. # 通过安装脚本来安装(如果centos6的系统可能不适合)

  5. curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py

  6. python get-pip.py


2、安装pyinstaller

  1. # 在7的系统上可以直接执行下面语句,经过测试最新3.4的版本还有一些不知名的问题

  2. # 当然不是所有的机器都能装上3.3版本,如果在安装的时候报ImportError....,就把版本降低试试

  3. pip install pyinstaller==3.3


  4. # 在6的系统上需要选择pyinstaller其他的版本,我在centos6.10上安装的是2.1的版本

  5. pip install pyinstaller==2.1


二、原理

简单的说一下pyinstaller的原理:
PyInstaller输入你指定的的脚本,首先分析脚本所依赖的其他脚本,然后去查找,复制,把所有相关的脚本收集起来,包括Python解析器,然后把这些文件放在一个目录下,或者打包进一个可执行文件里面。
可以直接发布输出的整个文件夹里面的文件,或者生成的可执行文件。你只需要告诉用户,你的应用App是自我包含的,不需要安装其他包,或某个版本的Python,就可以直接运行了。


需要注意的是(再次强调):PyInstaller打包的执行文件,只能在和打包机器系统同样的环境下。也就是说,不具备可移植性,若需要在不同系统上运行,就必须针对该平台进行打包。

三、使用

语法:

  1. pyinstaller [options] script [script ...] | specfile

参数介绍:

参数含义
-F指定打包后只生成一个可执行的文件
-D–onedir 创建一个目录,包含可执行,但会依赖很多文件(默认选项)
-c–console, –nowindowed 使用控制台,无界面(默认)
-w–windowed, –noconsole 使用窗口,无控制台
-p添加搜索路径,让其找到对应的库。
-i改变生成程序的icon图标

由于我只是一些脚本,所以基本都只用"-F"参数。
测试:
(1)、不带参数脚本

  1. [root@ecs-5704-0006 test]# cat test.py

  2. print("hello world")

测试一下脚本是否有问题:

  1. [root@ecs-5704-0006 test]# python test.py

  2. hello world

用pyinstaller打包:

  1. [root@ecs-5704-0006 test]# pyinstaller -F test.py

  2. 33 INFO: PyInstaller: 3.3

  3. 33 INFO: Python: 2.7.5

  4. 34 INFO: Platform: Linux-3.10.0-862.14.4.el7.x86_64-x86_64-with-centos-7.5.1804-Core

  5. 34 INFO: wrote /usr/local/src/test/test.spec

  6. 38 INFO: UPX is not available.

  7. 38 INFO: Extending PYTHONPATH with paths

  8. ['/usr/local/src/test', '/usr/local/src/test']

  9. 38 INFO: checking Analysis

  10. 38 INFO: Building Analysis because out00-Analysis.toc is non existent

  11. 38 INFO: Initializing module dependency graph...

  12. 40 INFO: Initializing module graph hooks...

  13. 91 INFO: running Analysis out00-Analysis.toc

  14. 103 INFO: Caching module hooks...

  15. 106 INFO: Analyzing /usr/local/src/test/test.py

  16. 106 INFO: Loading module hooks...

  17. 106 INFO: Loading module hook "hook-encodings.py"...

  18. 1764 INFO: Looking for ctypes DLLs

  19. 1764 INFO: Analyzing run-time hooks ...

  20. 1768 INFO: Looking for dynamic libraries

  21. 2032 INFO: Looking for eggs

  22. 2032 INFO: Using Python library /lib64/libpython2.7.so.1.0

  23. 2034 INFO: Warnings written to /usr/local/src/test/build/test/warntest.txt

  24. 2044 INFO: Graph cross-reference written to /usr/local/src/test/build/test/xref-test.html

  25. 2079 INFO: checking PYZ

  26. 2079 INFO: Building PYZ because out00-PYZ.toc is non existent

  27. 2079 INFO: Building PYZ (ZlibArchive) /usr/local/src/test/build/test/out00-PYZ.pyz

  28. 2245 INFO: Building PYZ (ZlibArchive) /usr/local/src/test/build/test/out00-PYZ.pyz completed successfully.

  29. 2273 INFO: checking PKG

  30. 2273 INFO: Building PKG because out00-PKG.toc is non existent

  31. 2273 INFO: Building PKG (CArchive) out00-PKG.pkg

  32. 4820 INFO: Building PKG (CArchive) out00-PKG.pkg completed successfully.

  33. 4829 INFO: Bootloader /usr/lib/python2.7/site-packages/PyInstaller/bootloader/Linux-64bit/run

  34. 4829 INFO: checking EXE

  35. 4829 INFO: Building EXE because out00-EXE.toc is non existent

  36. 4829 INFO: Building EXE from out00-EXE.toc

  37. 4829 INFO: Appending archive to ELF section in EXE /usr/local/src/test/dist/test

  38. 4841 INFO: Building EXE from out00-EXE.toc completed successfully.

然后会在脚本目录下生成build和dist目录,还有test.spec文件,我们需要的脚本就在dist目录下:

  1. [root@ecs-5704-0006 test]# cd dist/

  2. [root@ecs-5704-0006 dist]# ll

  3. total 15048

  4. -rwxr-xr-x 1 root root 4865824 Jun 19 17:21 test <---这就是我们需要的二进制文件

  5. [root@ecs-5704-0006 dist]# ./test

  6. hello world

(2)、带参数的脚本

  1. [root@ecs-5704-0006 test]# cat test2.py

  2. import sys

  3. print("hello {}".format(sys.argv[1]))

  4. [root@ecs-5704-0006 test]# python test2.py 12345

  5. hello 12345

用pyinstaller打包:

  1. [root@ecs-5704-0006 test]# pyinstaller -F test2.py

  2. 33 INFO: PyInstaller: 3.3

  3. 33 INFO: Python: 2.7.5

  4. 34 INFO: Platform: Linux-3.10.0-862.14.4.el7.x86_64-x86_64-with-centos-7.5.1804-Core

  5. 34 INFO: wrote /usr/local/src/test/test2.spec

  6. 37 INFO: UPX is not available.

  7. 38 INFO: Extending PYTHONPATH with paths

  8. ['/usr/local/src/test', '/usr/local/src/test']

  9. 38 INFO: checking Analysis

  10. 38 INFO: Building Analysis because out00-Analysis.toc is non existent

  11. 38 INFO: Initializing module dependency graph...

  12. 40 INFO: Initializing module graph hooks...

  13. 91 INFO: running Analysis out00-Analysis.toc

  14. 103 INFO: Caching module hooks...

  15. 106 INFO: Analyzing /usr/local/src/test/test2.py

  16. 106 INFO: Loading module hooks...

  17. 107 INFO: Loading module hook "hook-encodings.py"...

  18. 1777 INFO: Looking for ctypes DLLs

  19. 1777 INFO: Analyzing run-time hooks ...

  20. 1781 INFO: Looking for dynamic libraries

  21. 2047 INFO: Looking for eggs

  22. 2047 INFO: Using Python library /lib64/libpython2.7.so.1.0

  23. 2048 INFO: Warnings written to /usr/local/src/test/build/test2/warntest2.txt

  24. 2059 INFO: Graph cross-reference written to /usr/local/src/test/build/test2/xref-test2.html

  25. 2094 INFO: checking PYZ

  26. 2094 INFO: Building PYZ because out00-PYZ.toc is non existent

  27. 2094 INFO: Building PYZ (ZlibArchive) /usr/local/src/test/build/test2/out00-PYZ.pyz

  28. 2260 INFO: Building PYZ (ZlibArchive) /usr/local/src/test/build/test2/out00-PYZ.pyz completed successfully.

  29. 2288 INFO: checking PKG

  30. 2288 INFO: Building PKG because out00-PKG.toc is non existent

  31. 2288 INFO: Building PKG (CArchive) out00-PKG.pkg

  32. 4835 INFO: Building PKG (CArchive) out00-PKG.pkg completed successfully.

  33. 4843 INFO: Bootloader /usr/lib/python2.7/site-packages/PyInstaller/bootloader/Linux-64bit/run

  34. 4843 INFO: checking EXE

  35. 4843 INFO: Building EXE because out00-EXE.toc is non existent

  36. 4843 INFO: Building EXE from out00-EXE.toc

  37. 4843 INFO: Appending archive to ELF section in EXE /usr/local/src/test/dist/test2

  38. 4856 INFO: Building EXE from out00-EXE.toc completed successfully.

执行生成的二进制文件:

  1. [root@ecs-5704-0006 dist]# ./test2 9999999

  2. hello 9999999


最后,个人感觉pyinstaller的兼容性做的不是很好,虽然能解决安装包的麻烦,但是并没有提升运行效率,看自己的情况而定,不过可以保护源代码。


-END-

文章转载自乔克的好奇心,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论