原因
辛苦寫出來的程式, 最終目地就是要給別人用的嘛(賣給別人賺錢啊), 不然是寫辛酸的然後孤芳自賞嗎. 回想當初, 為了寫Python的程式, 要先安裝Python解譯器!! 而當老闆叫你show一下你的成品時, 你總不能因為老闆的電腦沒裝Python解譯器而叫他等個半小時幫他下載安裝先吧.
為了要在一台沒有安裝Python解譯器的電腦上執行我們的成果, 最方便的就是在exe檔按二下直接執行. 但解譯器怎麼辦? 當然就是把解譯器包進exe檔裏, 這樣就不用安裝Python解譯器了.
準備
將 .py檔包裝成 .exe檔, 需要 pyinstaller這支程式, 請由下面指令載入
pip install pyinstaller
包裝
pyinstaller有一些參數可以下達
-F : 要打包的 .py檔
-icon : 圖標路徑
-w : 使用視窗, 無控制台. wxPython也可以
-c : 使用控制台, 無視窗
–hidden-import=queue : 將相關模組全包進去
pyinstaller --hidden-import=queue -w -F .\win.py
經上述步驟, 會在根目錄產生幾個子目錄
1. build : 執行包裝程序時的一些暫存設定
2. dist : 這是最重要的一個目錄, 最終成品 .exe就在此處. 把這裏的 .exe檔 copy給別人, 就可以執行了, 而且對方不需安裝 Python解譯器.
OpenCv
如果有使用到 OpenCv套件的話,包裝會出現如下問題 : ImportError: OpenCV loader: missing configuration file: [‘config.py‘].
此時必需取得安裝 OpenCv 的路徑。請開啟一個測試檔,撰寫如下代碼
import cv2
print(cv2.__file__)
結果 :
D:\project\python\Projector\venv\lib\site-packages\cv2\__init__.py
然後將上述藍色部份,加入 –paths,如下所示
pyinstaller --hidden-import=queue -w -F Projector.py --paths="D:\project\python\Projector\venv\lib\site-packages\cv2"
打包圖片
底下是一般網路上的教法, 完全是錯誤的, 請不要用
1. pyi-makespec --hidden-import=queue -w -F DkLora.spec
2. 在mainFrame.spec加入
a.datas+=(('lora.png','D:\\project\\python\\DkLora\\lora.png', 'DATA'),)
3. pyinstaller -F DkLora.spec
正確的方法, 請參照本站的 Pyinstall內崁圖片
Selenium Failed to execute script xxxxx
打包成exe檔時,使用 pyinstaller –hidden-import=queue -w -F xxx.py,其中的 -w 為不顯示 DOS 控制台。
但如果有裝 selenium時,因為會使用 DOS 視窗提示訊息,所以下達 -w 無效,還是會強迫產生控制台視窗。解決方式,必需修改selenium的原始碼,請開啟如下檔案
C:\Users\使用者\AppData\Local\Programs\Python\Python37\Lib\site-packages\selenium\webdriver\common\service.py
Python 3.7版增加下面藍色的部份即可解決
def start(self): """ Starts the Service. :Exceptions: - WebDriverException : Raised either when it can't start the service or when it can't connect to the service """ try: cmd = [self.path] cmd.extend(self.command_line_args()) self.process = subprocess.Popen(cmd, env=self.env, close_fds=platform.system() != 'Windows', stdout=self.log_file, stderr=self.log_file ,stdin=PIPE,creationflags=134217728) except TypeError: raise
Python 3.8版增加下面藍色的部份即可解決
def _start_process(self, path: str) -> None: """ Creates a subprocess by executing the command provided. :param cmd: full command to execute """ cmd = [path] cmd.extend(self.command_line_args()) try: self.process = subprocess.Popen( cmd, env=self.env, close_fds=system() != "Windows", stdout=self.log_file, stderr=self.log_file, stdin=PIPE, #creationflags=self.creation_flags, creationflags=134217728, ) logger.debug(f"Started executable: `{self.path}` in a child process with pid: {self.process.pid}") except TypeError: raise