利用pyinstaller將python腳本打包發布


  之前寫了一個小工具,將excel配置表轉換為json、xml、lua等配置文件。最近在學習egret,正好需要轉換配置文件,剛好就用上了。然而當我想把工具拷到工作目錄時,就發愁了。之前我為了方便擴展,把程序拆分得太細:

xzc@xzc-HP-ProBook-4446s:~/Documents/code/github/py_exceltools$ ls -lh
總用量 80K
drwxrwxr-x 2 xzc xzc 4.0K  7月 27 23:03 bin
drwxrwxr-x 2 xzc xzc 4.0K  7月 27 23:03 client
-rw-rw-r-- 1 xzc xzc 7.7K  7月 27 23:03 decoder.py
-rw-rw-r-- 1 xzc xzc  893  7月 27 23:03 error.py
-rw-rw-r-- 1 xzc xzc  16K  7月 27 23:03 example.xlsx
-rw-rw-r-- 1 xzc xzc  131  7月 27 23:03 lancher.bat
-rw-rw-r-- 1 xzc xzc  127  7月 27 23:03 lancher.sh
-rw-rw-r-- 1 xzc xzc 3.9K  7月 27 23:03 loader.py
-rw-rw-r-- 1 xzc xzc  705  7月 27 23:03 loader.spec
-rw-rw-r-- 1 xzc xzc 2.4K  7月 27 23:03 README.md
drwxrwxr-x 2 xzc xzc 4.0K  7月 27 23:03 server
-rw-rw-r-- 1 xzc xzc 4.0K  7月 27 23:03 writer_json.py
-rw-rw-r-- 1 xzc xzc 7.2K  7月 27 23:03 writer_lua.py
-rw-rw-r-- 1 xzc xzc 5.6K  7月 27 23:03 writer_xml.py

如此多的文件,放到工作目錄不太好組織,也容易與項目的源代碼混在一起。畢竟我用的vs code分不清哪些才是工程內文件。何況以后還要給策划用,還得裝python和openpyxl庫,部署比較麻煩。於是想嘗試一下把python腳本打包為一個exe文件。

  google了一下,常用的工具不外乎pyinstaller和py2exe。兩者的功能都差不多,但是發現pyinstaller有一個參數 --onefile,即腳本都打包成單個可運行文件,這不正是我要的么。於是下載安裝來嘗試一下:

py_exceltools$pip install pyinstaller
py_exceltools$pyinstaller -F loader.py

...
tuple index out of range

安裝過程很順利,但是打包時卻報了個錯("tuple index out of range")。google一下"pyinstaller tuple index out of range",在github中發現是pyinstaller3.2.1不兼容python3.6.1。但是看看issue的回復,在dev版本是修復了。於是想試一下開發版本,不過看了一眼README,發現OS X、Linux、Win三個平台的CI都是failing:

想想還是算了吧,免得折騰半天又不能用。直接把本機的python從3.6.1降為3.5,再從新安裝pyinstaller,運行"pyinstaller -F loader.py"打包,一切順利,在dist目錄下生成了一個loader.exe。試運行下loader.exe,結果卻是這樣的:

Traceback (most recent call last):
File "loader.py", line 96, in <module>
options.timeout,options.suffix,options.srv_writer,options.clt_writer )
File "loader.py", line 25, in __init__
self.srv_writer = importlib.import_module( "writer_" + srv_writer )
File "importlib\__init__.py", line 126, in import_module
File "<frozen importlib._bootstrap>", line 986, in _gcd_import
File "<frozen importlib._bootstrap>", line 969, in _find_and_load
File "<frozen importlib._bootstrap>", line 956, in _find_and_load_unlocked
ImportError: No module named 'writer_lua'
Failed to execute script loader
請按任意鍵繼續. . .

缺失了模塊writer_lua,這是我自己寫的一個轉換為Lua配置的模塊。pyinstaller本來有分析腳本依賴的模塊的,但是我這個程序是根據運行時傳入的參數動態加載模塊的,因為我並不能預先知道用戶要把excel轉換為什么類型的文件。全部加載所有模塊,是一個解決方案,但不太合適,因為我本來的寫法是:規定了模塊的接口,新增模塊時,不需要修改我原有的代碼,會自動加載新模塊。再次搜索了一下,居然沒有找到相同的案例。閱讀了下pyinstaller的手冊(https://pythonhosted.org/PyInstaller/spec-files.html),發現可以用spec配置文件來打包各種數據的,比如程序的icon,甚至自定義的一些二進制文件。在http://pythonhosted.org/PyInstaller/when-things-go-wrong.html#listing-hidden-importshttp://pythonhosted.org/PyInstaller/hooks.html#understanding-pyinstaller-hooks中提到可以使用hiddenimports選項來導入隱藏的模塊。

  查看了下pyinstaller打包的過程,運行"pyinstaller -F loader.py"時確實在當前目錄下生成了一個loader.spec文件:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['loader.py'],
             pathex=['E:\\linux_share\\github\\py_exceltools'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='loader',
          debug=False,
          strip=False,
          upx=True,
          console=True )

在hiddenimports中加入自己動態加載的模塊,變成hiddenimports=['writer_lua','writer_xml','writer_json'],重新打包。注意,重新打包時不要再運行"pyinstaller -F loader.py"了,因為這個指令會重新生成spec文件,把你修改的覆蓋了。直接用"pyinstaller loader.spec"來打包。

  加入動態加載的模塊后,整個exe有7M多,運行正常。但是在64bit系統打包出來的程序,是64bit的,不能在32bit下運行。整個工具放在github上:https://github.com/changnet/py_exceltools

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM