You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写Python脚本自动安装MiKTeX、Strawberry Perl及Python包

Python脚本实现依赖全自动安装方案

核心逻辑是前置检测+静默安装,全程无需用户手动点击安装向导,适配Windows环境(MiKTeX、Strawberry Perl为Windows端文档生成场景的常用依赖),已安装的依赖会自动跳过,避免重复执行安装流程。


前置准备

  • 提前下载对应版本的MiKTeX、Strawberry Perl离线安装包,和你的Python脚本放在同一目录下分发,避免运行时网络波动导致安装失败
  • 整理好你的脚本需要的所有Python第三方包清单
  • 脚本开头默认申请管理员权限,满足系统软件安装的权限要求

完整实现代码

1. 基础导入与权限检测

把这段放在脚本最开头,自动申请管理员权限:

import sys
import os
import subprocess
import importlib
import ctypes
import winreg

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except Exception:
        return False

# 非管理员运行时自动提权
if not is_admin():
    print("[*] 正在申请管理员权限用于安装系统依赖...")
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join([f'"{arg}"' for arg in sys.argv]), None, 1)
    sys.exit(0)

2. Python依赖自动安装

自动检测Python包是否已安装,未安装则调用当前解释器对应的pip执行安装,避免安装到其他Python环境:

def install_python_pkg(import_name: str, pip_name: str = None):
    if pip_name is None:
        pip_name = import_name
    try:
        importlib.import_module(import_name)
        print(f"[√] Python依赖 {import_name} 已安装,跳过")
        return True
    except ImportError:
        print(f"[*] 正在安装Python依赖 {pip_name}...")
        install_cmd = [
            sys.executable, "-m", "pip", "install",
            "--user", pip_name,
            "--no-warn-script-location"
        ]
        res = subprocess.run(install_cmd, capture_output=True, text=True)
        if res.returncode != 0:
            print(f"[×] {pip_name} 安装失败:{res.stderr}")
            return False
        print(f"[√] {pip_name} 安装完成")
        return True

# 替换成你自己脚本需要的Python包列表:(导入名, pip安装名)
required_python_pkgs = [
    ("jinja2", None),
    ("pypandoc", None),
    ("markdown", None)
]
for pkg_import, pkg_pip in required_python_pkgs:
    install_python_pkg(pkg_import, pkg_pip)

3. 系统软件检测与静默安装

自动检测MiKTeX、Strawberry Perl是否已安装,未安装则调用离线安装包执行无交互静默安装,安装完成后自动刷新系统环境变量,无需重启电脑:

def get_latest_system_path():
    """从注册表读取最新的系统+用户环境变量Path,避免安装完环境变量不生效"""
    total_path = ""
    try:
        # 读取系统级Path
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", access=winreg.KEY_READ) as key:
            sys_path = winreg.QueryValueEx(key, "Path")[0]
        # 读取用户级Path
        with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Environment", access=winreg.KEY_READ) as key:
            user_path = winreg.QueryValueEx(key, "Path")[0]
        total_path = f"{sys_path};{user_path}"
    except Exception:
        pass
    return total_path

def check_software_installed(soft_display_name: str, exe_filename: str):
    """通过环境变量和注册表双重检测软件是否已安装"""
    # 先查现有Path里有没有对应执行文件
    for path_dir in os.environ.get("PATH", "").split(";"):
        if os.path.exists(os.path.join(path_dir, exe_filename)):
            print(f"[√] {soft_display_name} 已安装,跳过")
            return True
    # 查注册表卸载列表
    try:
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") as key:
            subkey_count = winreg.QueryInfoKey(key)[0]
            for i in range(subkey_count):
                subkey_name = winreg.EnumKey(key, i)
                with winreg.OpenKey(key, subkey_name) as subkey:
                    try:
                        current_name = winreg.QueryValueEx(subkey, "DisplayName")[0]
                        if soft_display_name.lower() in current_name.lower():
                            print(f"[√] {soft_display_name} 已安装,跳过")
                            return True
                    except OSError:
                        continue
    except Exception:
        pass
    return False

def install_system_software(installer_path: str, soft_name: str, silent_args: list):
    """执行静默安装"""
    if not os.path.exists(installer_path):
        print(f"[×] 未找到{soft_name}安装包,请将对应离线安装包放到脚本同目录后重试")
        return False
    print(f"[*] 正在静默安装{soft_name},耗时可能较长,请不要关闭窗口...")
    install_cmd = [installer_path] + silent_args
    res = subprocess.run(install_cmd, capture_output=True, text=True)
    if res.returncode != 0:
        print(f"[×] {soft_name}安装失败:{res.stderr}")
        return False
    # 刷新当前进程的环境变量
    os.environ["PATH"] = get_latest_system_path()
    print(f"[√] {soft_name}安装完成")
    return True

# 安装MiKTeX,替换成你实际打包的安装包文件名
if not check_software_installed("MiKTeX", "pdflatex.exe"):
    miktex_installer = os.path.join(os.path.dirname(os.path.abspath(__file__)), "basic-miktex-x64.exe")
    install_system_software(
        miktex_installer,
        "MiKTeX",
        ["--unattended", "--auto-install=yes", "--add-path=yes"]
    )

# 安装Strawberry Perl,替换成你实际打包的安装包文件名
if not check_software_installed("Strawberry Perl", "perl.exe"):
    perl_installer = os.path.join(os.path.dirname(os.path.abspath(__file__)), "strawberry-perl-5.38.x64.msi")
    install_system_software(
        perl_installer,
        "Strawberry Perl",
        ["/silent", "/norestart", "ADD_TO_PATH=1"]
    )

后续优化建议

  • 可以用PyInstaller把你的主脚本和上述安装逻辑打包成单个exe文件,用户拿到后只需要双击运行一次,所有依赖安装完成后自动进入你的文档生成功能
  • MiKTeX安装时加的--auto-install=yes参数会默认开启缺失宏包的静默下载,不会弹出确认窗口,适合无交互场景
  • 如果需要适配32位系统,只需要替换对应32位的安装包,增加系统架构判断逻辑选择对应安装包即可

内容的提问来源于stack exchange,提问作者Mike K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:27:23