PyInstaller打包python腳本的一些心得


因為在公司經常要幫同事做一個從excel表格中提取出需要的內容的重復工作,比較繁瑣還容易出錯;於是就想着要寫個程序,但是同事又不可能在電腦上也裝上python以及相關的包依賴(別人一看就覺得太麻煩而且太冗余),於是就想着將寫好的python腳本打包成exe,直接雙擊使用,方便快捷。

說干就干,先是花點時間寫完了腳本;然后搜索了相關的關鍵詞,找到了py2exe、PyInstaller、cx_Freeze等工具,最后確定使用PyInstaller

使用PyInstaller有幾個原因:

  • PyInstaller現在仍然在更新
  • PyInstaller使用方法簡單,py2exe比較繁瑣
  • PyInstaller網上教程比較多

安裝PyInstaller

推薦使用pip安裝

pip install pyinstaller -i https://pypi.douban.com/simple

后面加的-i https://pypi.douban.com/simple是使用豆瓣的源鏡像,在天朝速度會快很多;如果你擔心安全問題或者網速夠快,可以不加,使用官方的源。

安裝完后,直接

pyinstaller
usage: pyinstaller-script.py [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME] [-p DIR] [--hidden-import MODULENAME] [--additional-hooks-dir HOOKSPATH] [--runtime-hook RUNTIME_HOOKS] [--exclude-module EXCLUDES] [--key KEY] [-d] [-s] [--noupx] [-c] [-w] [-i <FILE.ico or FILE.exe,ID or FILE.icns>] [--version-file FILE] [-m <FILE or XML>] [-r RESOURCE] [--uac-admin] [--uac-uiaccess] [--win-private-assemblies] [--win-no-prefer-redirects] [--osx-bundle-identifier BUNDLE_IDENTIFIER] [--distpath DIR] [--workpath WORKPATH] [-y] [--upx-dir UPX_DIR] [-a] [--clean] [--log-level LEVEL] [--upx UPX] scriptname [scriptname ...] pyinstaller-script.py: error: the following arguments are required: scriptname 

可以看到PyInstaller的信息,說明安裝完成,可以使用了;詳細幫助可以pyinstaller -h查看。

使用PyInstaller

PyInstaller的使用非常簡單:

# 打包成一個文件
pyinstaller -F test.py
# 打包成文件夾(默認)
pyinstaller test.py

因為要精簡到底,所以我選擇打包成一個文件,打包完成后,打開dist文件夾,里面的那個exe文件就是打包好的程序,運行測試一下是否打包成功。

PyInstaller本身也是有很多選項的。這里挑幾個主要的說明一下:

  • -D, --one-dir打包成一個文件夾,默認
  • -F, --one-file打包成一個exe文件
  • -p DIR, --paths DIR添加路徑,一般用來添加程序所用到的包的所在位置
  • -c, --console, --nowindowed提供程序視窗,程序有輸入輸出的界面,默認
  • -w, --windowed, --noconsole無視窗,程序后台運行
  • -i <FILE.ico or FILE.exe,ID or FILE.icns>, --icon <FILE.ico or FILE.exe,ID or FILE.icns>添加icon圖標

openpyxl的一個錯誤

程序打包之后一定要測試一下是否能成功運行,不然會在同事面前出糗,另外還需要用另一台電腦測試一下。

當我試着運行程序時,發生了報錯:

Traceback (most recent call last):
  File "test.py", line 72, in <module>
  File "site-packages\pandas\core\frame.py", line 1414, in to_excel
  File "site-packages\pandas\io\excel.py", line 609, in __new__
  File "site-packages\pandas\io\excel.py", line 59, in get_writer
AttributeError: module 'openpyxl' has no attribute '__version__'
Failed to execute script test

於是就上網查找原因,一開始是去打包生成的build文件夾下面,查看一個名為warntest.txt的文件(這里是warn[yourscriptname].txt),發現有很多module都是miss,沒有加載到。

missing module named 'win32com.gen_py' - imported by win32com, c:\python35\lib\site-packages\PyInstaller\loader\rthooks\pyi_rth_win32comgenpy.py
missing module named sys.exc_info - imported by sys, openpyxl.reader.excel, win32com.server.dispatcher
missing module named pywintypes.IIDType - imported by pywintypes, win32com.client.dynamic
missing module named win32com.client._get_good_object_ - imported by win32com.client, win32com.client.util
...

於是就想着會不會是包的路徑沒有加載,嘗試着使用-p path去加載python下面儲存package的目錄,結果,重新打包一次仍然還是同樣的報錯。

於是我重新通過AttributeError: module 'openpyxl' has no attribute '__version__'去搜索結果,發現有人遇到同樣的bug,原因是使用了Pandas,但是pyinstaller在pandas引用的‘openpyxl’包中,無法讀取版本信息。*(一般使用Python處理科學數據都會使用到Pandas,我是處理excel文件的腳本,當然會用到openpyxl來讀寫excel)*

解決的辦法是在PyInstaller的hook文件夾中添加‘openpyxl’的一個讀取版本信息的hook。這個hook文件是在PyInstaller的Github issue上找到的。於是添加了這個hook,再重新打包,然后運行測試,終於成功了。

關於前面說到的warn[youscriptname].txt文件,有一種說法是如果你在其中沒有找到你所用到的包,那么里面的錯誤信息一般可以忽略,anyway,我是直接忽略掉的。

添加版本信息

辛辛苦苦寫了個程序,當然希望給程序簽個名;PyInstaller是可以添加你自己的個人版本信息的,詳細可以參考《Creating an Executable from a Python Script》,寫的非常詳細,依照相同的格式修改version.txt即可。但不知什么原因,我試了好幾次都沒有成功。如果以后找到原因,我再更新這篇文章。

關於32位和64位

這個算是后續劇情了。當把程序發給一位同事時,沒想到同事的win系統是32位的,而我一直使用的都是64位的系統和64位的程序,而PyInstaller好像沒有能選擇生成32位/64位exe的選項;也算是PyInstaller的一個缺點吧。最后我是安裝了32位的Python以及依賴的庫重新生成32位的exe才解決這個問題;所以以后也許生成32位的程序兼容性更好。

Reference

 


免責聲明!

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



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