環境健檢改(支援 EPUB 簡繁轉換所需套件)

建議檔名: Python_環境健檢(改).py


本版支援 EPUB 簡繁轉換所需套件(opencc、tqdm)
保留前版的 8 個套件檢查(向下相容)

🔑 主要改進

新增 opencctqdm 的檢查與安裝
✅ 匯出報告時加註「EPUB 轉換推薦安裝」提醒


處理 EPUB 時需要 zipfile 套件,這是 Python 內建
不需安裝,用來解壓/重新封裝 EPUB


opencc-python-reimplemented
核心簡繁轉換工具,支持自訂詞典,精確度高


tqdm
處理大量檔案時,顯示進度條


執行時會先產生目前安裝版本報告,並連網搜尋有無新版可更新。

無論是否進行更新,都會產生最終結果報告。


檢查報告1:

🔧 Python 環境健檢(10-modules stable)

==================================================

檢查時間(本地 UTC+8):2025/09/14 13:32:11


✔ 已安裝:beautifulsoup4 (4.13.5) — HTML/XML 解析 — https://www.crummy.com/software/BeautifulSoup/bs4/

✔ 已安裝:soupsieve (2.8) — CSS 選擇器支援 — https://github.com/facelessuser/soupsieve

✔ 已安裝:pypandoc (1.15) — 文件轉換工具 — https://github.com/bebraw/pypandoc

✔ 已安裝:requests (2.32.5) — HTTP 請求 — https://docs.python-requests.org/

✔ 已安裝:lxml (6.0.1) — 高效 XML/HTML 解析 — https://lxml.de/

✔ 已安裝:openpyxl (3.1.5) — Excel xlsx 讀寫 — https://openpyxl.readthedocs.io/

✔ 已安裝:python-docx (1.2.0) — Word .docx 操作 — https://github.com/python-openxml/python-docx

✔ 已安裝:python-pptx (1.0.2) — PowerPoint .pptx 操作 — https://github.com/scanny/python-pptx

✔ 已安裝:opencc-python-reimplemented (1.1.9) — 簡繁轉換 — https://pypi.org/project/opencc-python-reimplemented/

✔ 已安裝:tqdm (4.67.1) — 進度條顯示 — https://pypi.org/project/tqdm/


🔧 Python 環境健檢(最終結果)

==================================================

檢查時間(本地 UTC+8):2025/09/14 13:32:20


✔ 已安裝:beautifulsoup4 (4.13.5) — HTML/XML 解析 — https://www.crummy.com/software/BeautifulSoup/bs4/

✔ 已安裝:soupsieve (2.8) — CSS 選擇器支援 — https://github.com/facelessuser/soupsieve

✔ 已安裝:pypandoc (1.15) — 文件轉換工具 — https://github.com/bebraw/pypandoc

✔ 已安裝:requests (2.32.5) — HTTP 請求 — https://docs.python-requests.org/

✔ 已安裝:lxml (6.0.1) — 高效 XML/HTML 解析 — https://lxml.de/

✔ 已安裝:openpyxl (3.1.5) — Excel xlsx 讀寫 — https://openpyxl.readthedocs.io/

✔ 已安裝:python-docx (1.2.0) — Word .docx 操作 — https://github.com/python-openxml/python-docx

✔ 已安裝:python-pptx (1.0.2) — PowerPoint .pptx 操作 — https://github.com/scanny/python-pptx

✔ 已安裝:opencc-python-reimplemented (1.1.9) — 簡繁轉換 — https://pypi.org/project/opencc-python-reimplemented/

✔ 已安裝:tqdm (4.67.1) — 進度條顯示 — https://pypi.org/project/tqdm/


程式碼:
(複製以下文字,貼入純文字檔中,存檔後將副檔名設定為 .py)
【可直接在檔案總管雙擊執行】


#!/usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Python 環境健檢(10-modules stable + debug)

會在啟動時列出要檢查的套件清單與數量、目前 Python 解譯器與程式檔案路徑,

以方便確認你執行的就是此檔案。

"""


import importlib

import subprocess

import sys

import os

import json

datetime import datetime, timezone, timedelta


# ---------- 要檢查的 10 個套件(pip 名稱 -> (import 名稱, description)) ----------

PACKAGES = {

    "beautifulsoup4": ("bs4", "HTML/XML 解析 — https://www.crummy.com/software/BeautifulSoup/bs4/"),

    "soupsieve": ("soupsieve", "CSS 選擇器支援 — https://github.com/facelessuser/soupsieve"),

    "pypandoc": ("pypandoc", "文件轉換工具 — https://github.com/bebraw/pypandoc"),

    "requests": ("requests", "HTTP 請求 — https://docs.python-requests.org/"),

    "lxml": ("lxml", "高效 XML/HTML 解析 — https://lxml.de/"),

    "openpyxl": ("openpyxl", "Excel xlsx 讀寫 — https://openpyxl.readthedocs.io/"),

    "python-docx": ("docx", "Word .docx 操作 — https://github.com/python-openxml/python-docx"),

    "python-pptx": ("pptx", "PowerPoint .pptx 操作 — https://github.com/scanny/python-pptx"),

    "opencc-python-reimplemented": ("opencc", "簡繁轉換 — https://pypi.org/project/opencc-python-reimplemented/"),

    "tqdm": ("tqdm", "進度條顯示 — https://pypi.org/project/tqdm/"),

}

# ------------------------------------------------------------------------------


PAGE_LINES = 18  # 分頁顯示行數


def now_local_str():

    tz = timezone(timedelta(hours=8))

    return datetime.now(tz).strftime("%Y/%m/%d %H:%M:%S")


def get_installed_version(import_name, pip_name):

    try:

        module = importlib.import_module(import_name)

        version = getattr(module, "__version__", None)

        if not version:

            # 嘗試用 importlib.metadata 取得發行版版本

            try:

                if sys.version_info >= (3, 8):

                    importlib.metadata import version as dist_version

                else:

                    importlib_metadata import version as dist_version

                try:

                    version = dist_version(pip_name)

                except Exception:

                    version = None

            except Exception:

                version = None

        return version or "unknown"

    except Exception:

        return None


def page_print(lines):

    idx = 0

    total = len(lines)

    while idx < total:

        chunk = lines[idx: idx + PAGE_LINES]

        for l in chunk:

            print(l)

        idx += PAGE_LINES

        if idx < total:

            resp = input("按 Enter 顯示下一頁,輸入 q 以中止:").strip().lower()

            if resp == "q":

                break


def pip_install(package_name):

    cmd = [sys.executable, "-m", "pip", "install", package_name]

    print(f"執行:{' '.join(cmd)}")

    proc = subprocess.run(cmd)

    return proc.returncode == 0


def pip_upgrade(package_name):

    cmd = [sys.executable, "-m", "pip", "install", "--upgrade", package_name]

    print(f"執行:{' '.join(cmd)}")

    proc = subprocess.run(cmd)

    return proc.returncode == 0


def get_outdated_list():

    try:

        cmd = [sys.executable, "-m", "pip", "list", "--outdated", "--format=json"]

        proc = subprocess.run(cmd, capture_output=True, text=True)

        if proc.returncode == 0:

            try:

                data = json.loads(proc.stdout)

                return {item["name"].lower(): item for item in data}

            except Exception:

                return {}

        else:

            return {}

    except Exception:

        return {}


def main():

    print("🔧 Python 環境健檢(10-modules stable + debug)")

    print("="*50)

    print(f"執行檔案:{os.path.abspath(__file__)}")

    print(f"使用的 Python 解譯器:{sys.executable}")

    print(f"檢查時間(本地 UTC+8):{now_local_str()}\n")


    # 立刻列出要檢查的套件清單與數量(debug 用)

    keys = list(PACKAGES.keys())

    print(f"要檢查的套件數量:{len(keys)}")

    print("套件清單(pip 名稱):")

    for k in keys:

        print(" -", k)

    print()


    report_lines = []

    status = {}

    for pip_name, (import_name, desc) in PACKAGES.items():

        installed_version = get_installed_version(import_name, pip_name)

        if installed_version is None:

            report_lines.append(f"✘ 未安裝:{pip_name} — {desc}")

            status[pip_name] = {"installed": False, "import_name": import_name, "version": None, "desc": desc}

        else:

            report_lines.append(f"✔ 已安裝:{pip_name} ({installed_version}) — {desc}")

            status[pip_name] = {"installed": True, "import_name": import_name, "version": installed_version, "desc": desc}


    page_print(report_lines)


    # 匯出檢查結果

    ts = datetime.now(timezone(timedelta(hours=8))).strftime("%Y%m%d_%H%M%S")

    output_fn = f"套件檢查結果_10mod_{ts}.txt"

    with open(output_fn, "w", encoding="utf-8") as f:

        f.write("🔧 Python 環境健檢(10-modules stable)\n")

        f.write("="*50 + "\n")

        f.write(f"檢查時間(本地 UTC+8):{now_local_str()}\n\n")

        for pip_name, info in status.items():

            if info["installed"]:

                f.write(f"✔ 已安裝:{pip_name} ({info['version']}) — {info['desc']}\n")

            else:

                f.write(f"✘ 未安裝:{pip_name} — {info['desc']}\n")

    print(f"\n📄 檢查結果已輸出至:{output_fn}\n")


    # 安裝缺少的

    missing = [k for k, v in status.items() if not v["installed"]]

    if missing:

        ans = input(f"是否要安裝缺少的 {len(missing)} 個套件?(Y/N):").strip().lower()

        if ans == "y":

            for pip_name in missing:

                print(f"\n⏳ 正在安裝 {pip_name} ...")

                ok = pip_install(pip_name)

                if ok:

                    import_name = status[pip_name]["import_name"]

                    installed_ver = get_installed_version(import_name, pip_name)

                    if installed_ver is None:

                        print(f"⚠️ {pip_name} 安裝完成但無法 import,請檢查環境或重啟終端。")

                    else:

                        print(f"✅ {pip_name} 安裝並可匯入(版本:{installed_ver})")

                        status[pip_name]["installed"] = True

                        status[pip_name]["version"] = installed_ver

                else:

                    print(f"❌ {pip_name} 安裝失敗。")


    # 查是否有可更新的套件

    print("\n正在檢查是否有可更新的套件(pip list --outdated)...")

    outdated = get_outdated_list()

    our_outdated = []

    for pip_name in PACKAGES.keys():

        key = pip_name.lower()

        found = None

        if key in outdated:

            found = outdated[key]

        else:

            for k,v in outdated.items():

                if k.lower() == pip_name.lower():

                    found = v

                    break

        if found:

            our_outdated.append((pip_name, found))


    if our_outdated:

        lines = ["發現下列已安裝套件有新版:"]

        for pip_name, info in our_outdated:

            lines.append(f"- {pip_name}: 已安裝 {info.get('version')} → 最新 {info.get('latest')}")

        page_print(lines)

        ans2 = input("\n是否要更新上述套件?輸入 Y 更新全部,輸入 S 逐一選擇,輸入 N 跳過:").strip().lower()

        if ans2 == "y":

            for pip_name, _ in our_outdated:

                print(f"\n⏳ 正在更新 {pip_name} ...")

                ok = pip_upgrade(pip_name)

                if ok:

                    print(f"✅ 已更新 {pip_name}")

                else:

                    print(f"❌ 更新 {pip_name} 失敗。")

        elif ans2 == "s":

            for pip_name, info in our_outdated:

                choice = input(f"要更新 {pip_name}(已裝 {info.get('version')} → 最新 {info.get('latest')})嗎?(Y/N):").strip().lower()

                if choice == "y":

                    pip_upgrade(pip_name)

    else:

        print("沒有偵測到本機上這些套件有可用更新。")


    # 最終檢查輸出

    final_lines = []

    final_ts = datetime.now(timezone(timedelta(hours=8))).strftime("%Y%m%d_%H%M%S")

    final_fn = f"套件檢查結果_10mod_最終_{final_ts}.txt"

    for pip_name, (import_name, desc) in PACKAGES.items():

        ver = get_installed_version(import_name, pip_name)

        if ver is None:

            final_lines.append(f"✘ 未安裝:{pip_name} — {desc}")

        else:

            final_lines.append(f"✔ 已安裝:{pip_name} ({ver}) — {desc}")


    print("\n最終檢查結果:\n")

    page_print(final_lines)

    with open(final_fn, "w", encoding="utf-8") as f:

        f.write("🔧 Python 環境健檢(最終結果)\n")

        f.write("=" * 50 + "\n")

        f.write(f"檢查時間(本地 UTC+8):{now_local_str()}\n\n")

        for l in final_lines:

            f.write(l + "\n")

    print(f"\n📄 最終檢查結果已輸出至:{final_fn}\n")

    print("完成。")


if __name__ == "__main__":

    main()