PyInstaller可以將Python程序打包成一個exe程序來獨立運行,用戶使用時只需要執行這個exe文件即可,不需要在機器上再安裝Python及其他包就可運行了。另外,PyInstaller相較於其他打包程序,比如py2exe,大多時候使用起來更加方便,可以通過命令行的一些簡單命令即可進行打包,當然,當你需要打包的程序比較大且復雜時,使用哪個打包程序可能差別都不會太大了,這時候就看個人的習慣和愛好了。
pip安裝PyInstaller:pip install pyinstaller
pip更新PyInstaller:pip install --upgrade pyinstaller
pypi下載PyInstaller:https://pypi.org/project/PyInstaller/#files
注意:windows安裝PyInstaller時需要額外安裝另外兩個模塊,pywin32或pypiwin32,以及pefile,如果使用pip進行安裝,但是還沒有安裝pywin32時,會自動安裝pypiwin32,pefile沒有時也會自動安裝。
簡單打包命令
pyinstaller [-F/-D] [-w/-c] [-i xxx.ico] xxx.py/xxx.spec
- xxx.py/xxx.spec:需要打包的程序main文件或者spec文件。spec文件在使用py文件進行打包時會在相同路徑下自動生成,spec中的內容也是根據命令行中輸入的內容來生成的,也可以使用命令pyi-makespec [options] xxx.py來生成一個純粹的spec文件,而不會去執行打包的操作。
- -F/--onefile:將整個程序打包為一個exe文件,需要注意的是,與-D模式生成的exe程序相比,在啟動速度上會慢一點,原因是它需要先解壓exe文件並生成一個唯一的臨時環境來運行程序,關閉環境時也會自動刪除這個臨時環境,-D模式的程序本身就是解壓好的,運行完也不需要執行刪除操作,當程序比較大時,這個差別就很明顯了。
- -D/--onedir:默認選項,與F/--onefile參數作用相反,將程序打包為一個文件夾,文件夾中包含啟動程序的exe文件和其他依賴的資源文件和DLL文件等。
- -w:表示程序運行后隱藏命令行窗口,當你不需要使用命令行窗口作為程序的I/O時,比如GUI程序,可以使用這個參數選項。
- -c:默認選項,與-w相反,提供一個命令行窗口進行I/O。
- -i/--icon:指定exe程序圖標。
一般來說,大多數的程序,特別是一些小程序,使用這個命令就可以順利的打包了,也用不到其他復雜的參數選項。如果需要其他的知識點,以下的一些點可以參考下(這些點是自己在官方文檔上找的,有些並沒有經過驗證,有錯歡迎指正):
命令行指定參數選項方式打包:
- build文件夾:運行后會在同路徑下生成一個build文件夾,這個文件夾的作用相當於PyInstaller的工作空間,PyInstaller運行相關的文件和日志都在這個文件夾中,打包完成后可以直接刪除。
- dist文件夾:運行完成后會在同路徑下生成一個dist文件夾,這個文件夾下有一個跟程序同名的文件夾,打包好的exe程序就在這個文件夾下。
- 多py文件:如果命令行中指定的py文件不止一個,比如“pyinstaller xxx1.py xxx2.py”,pyinstaller會依次分析並執行,並把第一個py名稱作為spec和dist文件下的文件夾和程序的名稱。
- 其他常用參數選項:
- --specpath DIR:指定生成spec文件的路徑,默認為當前路徑。
- -n NAME/--name NAME:指定spec文件和程序的名稱,默認就是傳入的py腳本或spec文件的名稱。
- -h/--help:顯示PyInstaller幫助信息。
- -v/--version:顯示PyInstaller版本信息。
- --distpath DIR:指定生成dist的目錄,默認為“./dist”。
- --workpath WORKPATH:指定pyinstaller的工作目錄,即build文件夾,默認為“./build”。
- -y/--noconfirm:替換輸出目錄時不詢問,默認輸出目錄是“SPECPATH/dist/SPECNAME”。
- --upx-dir UPX_DIR:指定UPX程序的路徑,默認為“程序執行路徑”,即雙擊某個文件時,系統自動查找對應程序的路徑。UPX為一個壓縮程序,需要自行下載,可以將exe壓縮為zip格式的文件,並且壓縮效率非常高,如果打包后的exe程序非常大的話,為了避免客戶下載時文件太大的問題,可以使用這個UPX工具。
- --noupx:不需要UPX(即便可用)。
- -a/--ascii:不支持Unicode,默認為支持(如果可用的話)。
- --clean:在pyinstaller開始執行之前清除緩存並刪除臨時文件(一般存儲在C:\Users\Administrator\AppData\Roaming\pyinstaller)。
- --log-level LEVEL:指定打印的日志等級,默認為INFO,日志等級有:TRACE,DEBUG,INFO,WARN,ERROR,CRITICAL。如果在打包時遇到了問題,為了方便定位問題,可以使用這個參數來查看特定級別的日志信息。
- 數據綁定和搜索相關的參數選項:
- --add-data SRC;DEST:指定需要添加非二進制文件路徑或者文件夾路徑,比如圖片和pdf文件等,這個選項可以使用多次。這個命令其實就是將需要的文件或者文件夾拷貝到指定的路徑下,在-D模式下,可以看情況在程序打包完成后自己手動拷貝過去。
- --add-binary SRC;DEST:指定需要添加的二進制文件路徑,比如DLL文件、動態鏈接庫或者共享文件對象等,這個選項可以使用多次。同-add-data命令一樣,是一個拷貝數據的功能。
- -p DIR/--paths DIR:指定import語句的查找路徑(與PYTHONPATH一樣),多個路徑之間可以使用分號“;”連接,或者多次使用這個選項來進行指定。
- --hidden-import MODULENAME/--hiddenimport MODULENAME:指定腳本中需要隱式導入的模塊,比如在__import__、imp.find_module()、exec、eval等語句中導入的模塊,這些模塊PyInstaller是找不到的,需要手動指定導入,這個選項可以使用多次。
- --additional-hooks-dir HOOKSPATH:指定額外hook文件(可以是py文件)的查找路徑,這些文件的作用是在PyInstaller運行時改變一些Python或者其他庫原有的函數或者變量的執行邏輯(並不會改變這些庫本身的代碼),以便能順利的打包完成,這個選項可以使用多次。
- --runtime-hook RUNTIME_HOOKS:指定自定義的運行時hook文件路徑(可以是py文件),在打好包的exe程序中,在運行這個exe程序時,指定的hook文件會在所有代碼和模塊之前運行,包括main文件,以滿足一些運行環境的特殊要求,這個選項可以使用多次。
- --exclude-module EXCLUDES:指定可以被忽略的可選的模塊或包,因為某些模塊只是PyInstaller根據自身的邏輯去查找的,這些模塊對於exe程序本身並沒有用到,但是在日志中還是會提示“module not found”,這種日志可以不用管,或者使用這個參數選項來指定不用導入,這個選項可以使用多次。
- --key KEY:指定用於Python字節碼加密的key,key是一個16個字符的字符串。
- -D模式程序的運行:運行程序的時候,其實開始運行的是一個pyinstaller生成的引導加載程序bootloader,bootloader是根據不同的操作系統生成的,運行bootloader時,會創建一個臨時的Python環境以便運行Python程序,所以使用exe程序時不用安裝Python也能運行這個程序。
- -F模式程序的運行:也會有一個BootLoader,但是會根據操作系統創建一個名為_MEIxxxxxx的文件夾,用作這個程序的臨時運行環境(不只是Python環境),這個xxxxxx是一個隨機的數字。-F模式程序啟動的時候因為需要解壓並拷貝依賴和資源文件到臨時運行環境_MEIxxxxxx,所以啟動速度是比-D模式程序要慢的,運行結束后會刪除臨時運行環境的文件夾。在Linux和相關系統中,可能有“no-execution”選項,但是對於-F模式程序是不兼容的。由於_MEIxxxxxx是唯一的,所以可以同時運行多個程序,多個程序時互不干涉的。如果程序崩潰了,或者強行結束了(比如在Windows的任務管理器中殺死了進程),_MEIxxxxxx文件夾是不會被刪除的,所以頻繁崩潰或者結束進程會導致有多個_MEIxxxxxx文件夾,會非常占用磁盤空間,可以使用--runtime-temdir指定_MEIxxxxxx的存放位置。-F模式程序如果在運行時遇到了權限問題,可以使用-D模式程序替代。
- shell腳本/批處理腳本:使用命令行打包時,可能需要指定的參數選項很多,這時候可以將需要執行的全部命令信息,包括這些參數選項的指定,都放在一個shell腳本或者批處理文件中來執行。
- 運行時信息:
- __file__: 所有基於模塊的使用到__file__屬性的代碼,在源碼運行時表示的是當前腳本的絕對路徑,但是打包后就是當前模塊的模塊名(即文件名xxx.py)。
- sys.frozen:源碼運行時沒有這個屬性,打包后的程序添加了這個屬性,值為True。
- sys._MEIPASS: 源碼運行時沒有這個屬性,打包后的程序添加了這個屬性,表示程序運行的絕對路徑。對於-D模式程序,表示的是這個exe程序所在文件夾的絕對路徑,對於-F模式程序表示的是_MEIxxxxxx的文件夾絕對路徑,_MEIxxxxxx為exe解壓后創建的臨時運行環境的文件夾名稱,對於exe程序每一次運行來說,它是唯一的。
- sys.excutable:代碼運行時表示運行的解釋器絕對路徑,如C:\Python36\python.exe,在打包的程序中就是exe程序文件的絕對路徑,這個是用來定位用戶運行該程序的真實位置。
- sys.argv[0]:一般來說就是運行程序的絕對路徑,但是在不同平台或者不同的方式啟動程序時,會有所不同,比如通過符號鏈接運行的程序sys.argv[0]就是符號名稱,而不是真實的程序路徑。
- 數據文件的修改:--add-data這種通過拷貝形式的數據文件,在-D模式下如果在運行時修改了,那么對應的數據文件是真的被修改了,但是在-F模式下,由於每次運行會單獨創建一個臨時運行環境,修改的內容也是臨時運行環境中的內容,並且運行完后會自動刪除臨時運行環境,所以這種數據文件是無法直接更改exe中的數據文件的,也就意味着每次運行程序,數據文件都會是exe程序中原來的那一份,修改的內容會隨着臨時運行環境的關閉而刪除了,不會同步到exe程序中的。
- 發生錯誤時:
- 當發生“module not found”警告時,其實很多找不到對應模塊的消息都不用管,只是PyInstaller根據自身的邏輯去查找的,因為它們並不是跟你的最終程序有關的。
- 當發生導入失敗時,這才是真正的錯誤,需要去關注和解決的。
- 當打包成功,且中間沒有發生任何警告提示,但是運行程序時提示某個模塊找不到,可能就是“--hidden-import=”的問題了,當使用__import__、imp.find_module()、exec、eval或者Python/C API時,pyinstaller不會自動去導入這些里面涉及的導包,所以這些包就需要使用“--hidden-import=”來指定具體需要導入的包了。
- --runtime-hook=xxx.py中指定的py會依次在打包的主程序main腳本之前運行,可以用來改變一些函數或者變量,以滿足特殊場景的要求。
spec配置文件方式打包
- 生成spec文件:pyi-makespec [options] xxx.py [other scripts...],生成spec文件時可以什么都不指定,然后在生成的spec文件中單獨配置,默認為-D模式下的spec文件,也可以指定生成-F模式的spec文件。當然也可以在第一次就將參數選項指定好,以后就只維護spec文件。
- 參數選項:生成spec文件的參數選項和命令行模式下執行PyInstaller打包是完全一樣的。
- spec文件類型:spec文件其實就是一個py文件,在編輯時可以直接將它當成一個py文件來使用。
- spec文件優勢:一般情況而言,直接使用PyInstaller命令行直接打包即可,但是以下情況使用spec文件的話會方便一些:
- 程序需要綁定一些數據文件,可以在spec文件中單獨用一個列表變量來指定,可讀性和可維護性會高很多。
- 需要include一些PyInstaller不知道的動態鏈接庫,如:.dll/.so文件,同樣可以在spec文件中單獨用一個列表變量來指定。
- 需要往可執行文件中添加一些運行時選項,如hook文件。
關於spec文件:
-
如果有需要,可以通過PyCharm、eclipse等工具打開安裝目錄中的PyInstaller文件夾來查看源碼信息
- a:Analysis類的實例,要求傳入各種腳本用於分析程序的導入和依賴。a中內容主要包括以下四部分:scripts,即可以在命令行中輸入的Python腳本;pure,程序代碼文件中的純Python模塊,包括程序的代碼文件本身;binaries,程序代碼文件中需要的非Python模塊,包括--add-binary參數指定的內容;datas,非二進制文件,包括--add-data參數指定的內容。
- pyz:PYZ的實例,是一個.pyz文件,包含了所有pure中的所有Python模塊。
- exe:EXE類的實例,這個類是用來處理Analysis和PYZ的結果的,也是用來生成最后的exe可執行程序。
- coll:COLLECT類的實例,用於創建輸出目錄。在-F模式下,是沒有COLLECT實例的,並且所有的腳本、模塊和二進制文件都包含在了最終生成的exe文件中。
- Analysis參數scripts:也是第一個參數,它是一個腳本列表,可以傳入多個py腳本,效果與命令行中指定多py文件相同,即py文件不止一個時,比如“pyinstaller xxx1.py xxx2.py”,pyinstaller會依次分析並執行,並把第一個py名稱作為spec和dist文件下的文件夾和程序的名稱。
- Analysis參數pathex:同命令“-p DIR/--paths DIR”,其實默認就有一個spec的目錄,如果使用命令添加的話,會首先添加命令中指定的目錄,再添加默認的路徑。
- Analysis參數datas:即添加數據文件,命令是--add-data,spec文件中是Analysis的datas=[]參數,datas是一個元素為元組的列表,每個元組有兩個元素,都必須是字符串類型,元組的第一個元素為數據文件或文件夾,元組的第二個元素為運行時這些文件或文件夾的位置。例如:datas=[('src/README.txt', '.'), ],也可以在命令行中這樣寫:pyinstaller --add-data 'src/README.txt;.' myscript.py,表示打包時將文件src/README.txt添加(copy)到相對於spec文件的根目錄下,指定文件時是相對於spec來進行尋找的,而不是要打包的exe程序路徑。也可以使用通配符:datas= [ ('/mygame/sfx/*.mp3', 'sfx' ) ],表示將/mygame/sfx/目錄下的所有.mp3文件都copy到sfx文件夾中。也可以添加整個文件夾:datas= [ ('/mygame/data', 'data' ) ],表示將/mygame/data文件夾下所有的文件都copy到data文件夾下。
- Analysis參數binaries:添加二進制文件,效果同命令--add-binary,也是一個列表,定義方式與datas參數一樣。
- Analysis參數hiddenimports:同命令“--hidden-import MODULENAME/--hiddenimport MODULENAME”。
- Analysis參數hookspath:同命令“--additional-hooks-dir HOOKSPATH”。
- Analysis參數runtime_hooks:同命令“--runtime-hook RUNTIME_HOOKS”。
- Analysis參數excludes:同命令“--exclude-module EXCLUDES”。
- exe參數console:設置是否顯示命令行窗口,和命令-w/-c作用一樣。
- exe參數icon:設置程序圖標,和命令-i/--icon作用一樣。某些情況,直接執行“pyinstaller xxx.py”時生成的spec中沒有這個參數,需要手動添加,參數值就是圖片路徑的字符串。
- PyInstaller全局變量:這些全局變量可以在spec文件使用。
- DISTPATH:相對於dist文件夾的相對路徑,如果--distpath參數選項被指定了,則使用被指定的參數值。
- HOMEPATH:pyinstaller查找的絕對路徑,一般是Python解釋器的site-packages文件夾的絕對路徑。
- SPEC:在命令行中指定的spec文件路徑。
- SPECPATH:os.path.split(SPEC)的第一個值。
- specnm:spec文件的文件名,不含文件類型后綴。
- workpath:相對於build文件夾的相對路徑,如果workpath=參數選項被指定了,這使用被指定的值。
- WARNFILE:在build文件夾中警告文件的全路徑,一般是warn-myscript.txt
- 指定了相同的參數:當命令行和spec中指定了相同的參數選項,那么命令行的參數選項會被忽略。
遇到的問題和解決方案:
1.問題描述:
打包時報如下異常:
File "c:\python36\lib\site-packages\PyInstaller\hooks\pre_safe_import_module\hook-setuptools.extern.six.moves.py", line 34, in pre_safe_import_module
for real_module_name, six_module_name in real_to_six_module_name.items():
AttributeError: 'str' object has no attribute 'items'
解決方案:
使用命令“pip install --upgrade setuptools”更新三方庫setuptools