前言
前段時間做一個內網開發的需求,要求將selenium程序打包成.exe放在內網的win7上運行,在掘金搜了一圈也沒有發現相關文章,因此將過程中踩到的坑記錄分享一下。
本文涵蓋了具體打包操作、不同模塊和依賴項的兼容性解決方案,以確保在打包和運行時都能正常工作。
1. 背景
在 Python 項目中,使用第三方庫(如 selenium
、selenium-wire
、mitmproxy
等)時,會遇到許多依賴項,并且由于庫之間的版本兼容性問題,可能導致運行時錯誤。常用的打包工具 PyInstaller
能將 Python 項目打包成單個可執行文件,但也會因為兼容性問題和路徑管理而出現各種運行錯誤。因此,本指南總結了打包過程中常見問題和解決方案,以幫助開發者順利完成項目的打包和發布。
2. 可能遇到的問題概述
在PyInstaller
打包selenium-wire
時可能會遇到一些問題,如下:
- 依賴沖突:如
pyOpenSSL
與cryptography
的版本沖突問題。 - 路徑問題:如
chromedriver.exe
在運行時未找到或未正確加載。 - 打包文件缺失:某些文件(如
.crt
、.key
、chromedriver.exe
等)在打包時未包含,導致運行時無法找到。
3. PyInstaller 打包步驟及參數配置
使用 PyInstaller
打包一個 Python 項目時,可以通過以下步驟和命令來生成可執行文件:
pyinstaller --onefile --clean --hidden-import=<module> --name=<executable_name> <script.py>
參數詳解:
--onefile
:將所有文件打包成一個獨立可執行文件。--clean
:清理之前打包時的緩存,確保使用最新的依賴版本。--hidden-import
:指定打包時包含的隱藏模塊(PyInstaller 有時無法自動檢測到的依賴)。--name
:指定打包生成的可執行文件名稱。
對于使用 .spec
文件的項目,可以通過如下命令打包:
pyinstaller --clean <spec_file_name>.spec
4. 依賴項版本不兼容問題
4.1 pyOpenSSL
和 cryptography
的兼容性問題
在 PyInstaller
打包的項目中,pyOpenSSL
和 cryptography
是常見依賴。由于版本更新問題,某些版本的 pyOpenSSL
可能無法與較新版本的 cryptography
兼容,導致運行時 X509_V_FLAG_NOTIFY_POLICY
等屬性缺失。
常見錯誤:
AttributeError: module 'lib' has no attribute 'X509_V_FLAG_NOTIFY_POLICY'
解決方法:
- 降級
cryptography
版本:建議降級到3.3.2
版本,確保兼容性。
pip install cryptography==3.3.2
- 降級
pyOpenSSL
版本:使用20.0.1
版本,這與cryptography 3.3.2
更加兼容。
pip install pyOpenSSL==20.0.1
- 升級所有相關依賴:如果使用較舊的版本無效,嘗試升級
selenium-wire
、mitmproxy
、pyOpenSSL
、和cryptography
,確保依賴版本相互兼容。
pip install --upgrade selenium-wire mitmproxy pyOpenSSL cryptography
4.2 chromedriver.exe
打包問題
selenium
使用的 chromedriver.exe
必須在系統的 PATH
中或由代碼顯式指定路徑。然而,打包成單文件后,chromedriver.exe
可能無法正常找到,需要手動配置。
5. 路徑問題及解決方法
5.1 包含 chromedriver.exe
文件
將 chromedriver.exe
文件放在項目目錄下,并在 .spec
文件的 datas
配置中包含此文件,以確保在打包后可以正確引用。
配置示例:
- 在
.spec
文件中將chromedriver.exe
添加到datas
:
datas=[('<absolute_path>/chromedriver.exe', '.') # 打包到可執行文件的根目錄
]
- 在代碼中設置相對路徑以引用
chromedriver.exe
文件,確保在打包后的運行環境中可以正確定位到該文件。
from selenium.webdriver.chrome.service import Service
import os
import sysdef resource_path(relative_path):if hasattr(sys, '_MEIPASS'):return os.path.join(sys._MEIPASS, relative_path)return os.path.join(os.path.abspath("."), relative_path)chrome_driver_path = resource_path("chromedriver.exe")
service = Service(executable_path=chrome_driver_path)
6. 詳細解決方案
在打包過程中,還可能遇到其他常見問題,例如文件緩存和打包依賴文件丟失問題。
6.1 清理緩存文件
在打包前,通過 --clean
參數或手動刪除 build
和 dist
文件夾,確保 PyInstaller
不使用緩存文件:
pyinstaller --clean <spec_file_name>.spec
或者手動刪除 build
和 dist
文件夾:
rmdir /s /q build
rmdir /s /q dist
.spec
文件配置 hiddenimports
6.2 使用 如果 PyInstaller
在打包時無法自動識別所有依賴,可以通過 .spec
文件中的 hiddenimports
參數顯式指定依賴項:
hiddenimports=['mitmproxy', 'seleniumwire', 'OpenSSL', 'cryptography'],
6.3 將證書文件包含在打包中
某些依賴(如 selenium-wire
)使用的 .crt
和 .key
文件也需手動包含:
datas=[('<absolute_path>/seleniumwire/ca.crt', 'seleniumwire'),('<absolute_path>/seleniumwire/ca.key', 'seleniumwire')
],
7. 調試建議
- 確保依賴版本一致:在開發和打包環境中使用相同的依賴版本,防止版本不一致帶來的兼容性問題。
- 使用虛擬環境:每個項目單獨配置虛擬環境,避免全局環境中的其他依賴引發沖突。
- 分步調試:打包前在開發環境中逐步測試依賴是否正常運行。遇到依賴問題,優先使用兼容的版本組合。
調試依賴沖突
使用 pip check
命令檢查依賴沖突,并通過 pip freeze
獲取依賴列表,以便管理版本:
pip check # 檢查依賴沖突
pip freeze > requirements.txt # 保存當前依賴
總結
本指南總結了在使用 PyInstaller
打包 Python 項目時常見的兼容性問題和解決方法。通過以下步驟,可以顯著提升打包的成功率:
- 使用兼容的依賴版本,尤其是
pyOpenSSL
和cryptography
。 - 將
chromedriver.exe
等可執行文件顯式添加到.spec
文件。 - 在代碼中使用
sys._MEIPASS
以正確引用打包后臨時解壓目錄中的文件。
嚴格遵循這些步驟可以有效避免大多數打包和運行時錯誤,確保項目在各個環境下穩定運行。