在上一篇文章中,我們梳理了如果編寫一個(gè)啟動(dòng)本地服務(wù)的py代碼。但執(zhí)行它需要有python環(huán)境。
為了方便拷貝到?jīng)]有python環(huán)境的電腦使用,考慮把它打包成exe(windows系統(tǒng)電腦)。
1 代碼補(bǔ)充
python.py的代碼對資源路徑做補(bǔ)充處理:
import sys
import os
import http.server
import socketserver
# 定義服務(wù)器端口
PORT = 50000
# 獲取打包后的資源路徑
def 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)
# 定義 HTML 頁面文件(使用資源路徑)
index_file = resource_path('iat-js-demo/example/wxl/index.html')
class MyHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.path = '/' + index_file
return super().do_GET()
with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
print(f"服務(wù)器已啟動(dòng),訪問地址: http://localhost:{PORT}")
# 啟動(dòng)服務(wù)器,開始監(jiān)聽請求
httpd.serve_forever()
2 安裝pyinstaller
安裝打包工具(在項(xiàng)目目錄中執(zhí)行):
# 這個(gè)成功率比較低
pip install pyinstaller
# 阿里云鏡像源,成功率高
pip install pyinstaller -i https://mirrors.aliyun.com/pypi/simple/
# 清華大學(xué)鏡像源
pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple
3 打包程序
在命令行中,切換到 server.py 文件所在的目錄,然后執(zhí)行以下命令進(jìn)行打包:
pyinstaller --onefile --add-data "js-demo;js-demo" -n server server.py
- --onefile :將所有依賴項(xiàng)打包成一個(gè)單獨(dú)的可執(zhí)行文件。
--add-data "js-demo;js-demo" :將 js-demo 目錄下的所有文件添加到打包后的程序中,并保持目錄結(jié)構(gòu)不變。 - -n server :指定打包后的可執(zhí)行文件的名稱為 server.exe 。
打包成功后,會在目錄生成一個(gè)dist文件夾,文件夾里面有一個(gè)server.exe。
(build 目錄會在打包過程中生成,它主要包含一些打包過程中產(chǎn)生的臨時(shí)文件和中間文件。)
4 拷貝html
把要訪問的html網(wǎng)頁拷貝到server.exe同級目錄。
5 測試訪問網(wǎng)頁
雙擊server.exe,啟動(dòng)本地服務(wù),監(jiān)聽端口在50000.
在瀏覽器中輸入localhost:50000/index.html 即可訪問網(wǎng)頁。
6 其他:打包無控制臺的exe
若要打包沒有命令行窗口的exe,可以加上參數(shù)--noconsole。
pyinstaller --onefile --noconsole -n ServerApp server.py
但要注意當(dāng)使用 --noconsole 選項(xiàng)打包 Python 腳本為 EXE 文件時(shí),程序會在無控制臺模式下運(yùn)行,這可能會導(dǎo)致一些依賴于控制臺輸出或標(biāo)準(zhǔn)輸入輸出的代碼出現(xiàn)問題。如果發(fā)現(xiàn)報(bào)錯(cuò)信息'NoneType' object has no attribute 'write' ,通常與標(biāo)準(zhǔn)輸出或日志記錄相關(guān),因?yàn)樵跓o控制臺模式下,標(biāo)準(zhǔn)輸出( sys.stdout )和標(biāo)準(zhǔn)錯(cuò)誤( sys.stderr )可能會被設(shè)置為 None 。
問題分析
在無控制臺模式下, SimpleHTTPRequestHandler 類可能會嘗試使用標(biāo)準(zhǔn)輸出進(jìn)行日志記錄或錯(cuò)誤處理,而此時(shí)標(biāo)準(zhǔn)輸出為 None ,從而導(dǎo)致錯(cuò)誤。
解決方案
可以通過重定向標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤到日志文件來解決這個(gè)問題。在代碼中添加以下邏輯,確保在無控制臺模式下也能正常處理日志記錄。
# 重定向標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤到日志文件
if hasattr(sys, '_MEIPASS'): # 檢查是否為打包環(huán)境
sys.stdout = open(os.devnull, 'w')
sys.stderr = open('server_error.log', 'w')
參考內(nèi)容:
通過Trae(CN)Chat模式下完成該流程。