python打包一個(gè)啟動(dòng)本地服務(wù)功能為exe

在上一篇文章中,我們梳理了如果編寫一個(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模式下完成該流程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容