如何用Python获取Windows、Linux系统已装应用及版本?求跨平台脚本实现方案
Absolutely! You can totally pull off retrieving installed apps and their version details on both Windows and Linux with Python. Let's break this down step by step—first covering each OS-specific approach, then combining them into a cross-platform script.
Most desktop apps installed on Windows leave entries in the Windows Registry, specifically under the Uninstall keys. We can use Python's built-in winreg module to access these entries and extract app names and versions.
核心思路
We'll check two registry paths to cover both 64-bit and 32-bit apps:
SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall(for 64-bit apps)SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall(for 32-bit apps running on 64-bit Windows)
代码实现
import winreg def get_windows_apps(): apps = [] # 定义要查询的注册表路径 registry_paths = [ r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", r"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" ] for path in registry_paths: try: # 打开本地机器的注册表键 with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path) as root_key: # 获取子键数量,遍历所有子键 subkey_count = winreg.QueryInfoKey(root_key)[0] for i in range(subkey_count): try: subkey_name = winreg.EnumKey(root_key, i) with winreg.OpenKey(root_key, subkey_name) as app_key: # 读取应用名称,跳过无名称的项 try: app_name = winreg.QueryValueEx(app_key, "DisplayName")[0] except FileNotFoundError: continue # 读取版本号,无版本则标记为Unknown try: app_version = winreg.QueryValueEx(app_key, "DisplayVersion")[0] except FileNotFoundError: app_version = "Unknown" apps.append({"name": app_name, "version": app_version}) except (OSError, FileNotFoundError): # 跳过无法访问的子键(比如权限不足) continue except PermissionError: print("⚠️ 提示:需要管理员权限才能读取全部应用信息,部分系统应用可能无法获取") continue # 去重,避免32/64位重复项 return list({app["name"]: app for app in apps}.values())
Linux doesn't have a centralized registry like Windows—installed apps are managed by package managers (dpkg, rpm, flatpak, snap, etc.). We'll detect which package managers are available, run their list commands, and parse the output.
核心思路
- Check for common package managers (dpkg for Debian/Ubuntu, rpm for RHEL/CentOS, flatpak/snap for universal apps)
- Run the appropriate command to get app names and versions
- Parse the command output into a structured list
代码实现
import subprocess def get_linux_apps(): apps = [] # 定义包管理器的命令、参数和解析规则 package_managers = [ # Debian/Ubuntu系:dpkg-query ("dpkg-query", ["-W", "-f=${Package}\t${Version}\n"], lambda line: line.split('\t')), # RHEL/CentOS/Fedora系:rpm ("rpm", ["-qa", "--queryformat=%{NAME}\t%{VERSION}\n"], lambda line: line.split('\t')), # Flatpak通用应用 ("flatpak", ["list", "--columns=name,version"], lambda line: line.split('\t')), # Snap通用应用 ("snap", ["list"], lambda line: line.split()[0:2]) ] for pm_cmd, pm_args, parser in package_managers: try: # 先检查包管理器是否存在 subprocess.run([pm_cmd, "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 执行获取列表的命令 result = subprocess.run([pm_cmd] + pm_args, capture_output=True, text=True, check=True) # 解析输出内容 for line in result.stdout.split('\n'): line = line.strip() # 跳过表头和空行 if not line or line.startswith(("Name", "Package", "Command")): continue parts = parser(line) if len(parts) >= 2: app_name = parts[0].strip() app_version = parts[1].strip() apps.append({"name": app_name, "version": app_version}) except (subprocess.CalledProcessError, FileNotFoundError): # 包管理器不存在或执行失败,跳过 continue # 去重,避免同一应用在多个包管理器中重复出现 return list({app["name"]: app for app in apps}.values())
Now let's combine the two functions into a single script that automatically detects the OS and runs the appropriate logic.
import os def get_windows_apps(): import winreg apps = [] registry_paths = [ r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", r"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" ] for path in registry_paths: try: with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path) as root_key: subkey_count = winreg.QueryInfoKey(root_key)[0] for i in range(subkey_count): try: subkey_name = winreg.EnumKey(root_key, i) with winreg.OpenKey(root_key, subkey_name) as app_key: try: app_name = winreg.QueryValueEx(app_key, "DisplayName")[0] except FileNotFoundError: continue try: app_version = winreg.QueryValueEx(app_key, "DisplayVersion")[0] except FileNotFoundError: app_version = "Unknown" apps.append({"name": app_name, "version": app_version}) except (OSError, FileNotFoundError): continue except PermissionError: print("⚠️ 提示:需要管理员权限才能读取全部应用信息,部分系统应用可能无法获取") continue return list({app["name"]: app for app in apps}.values()) def get_linux_apps(): import subprocess apps = [] package_managers = [ ("dpkg-query", ["-W", "-f=${Package}\t${Version}\n"], lambda line: line.split('\t')), ("rpm", ["-qa", "--queryformat=%{NAME}\t%{VERSION}\n"], lambda line: line.split('\t')), ("flatpak", ["list", "--columns=name,version"], lambda line: line.split('\t')), ("snap", ["list"], lambda line: line.split()[0:2]) ] for pm_cmd, pm_args, parser in package_managers: try: subprocess.run([pm_cmd, "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = subprocess.run([pm_cmd] + pm_args, capture_output=True, text=True, check=True) for line in result.stdout.split('\n'): line = line.strip() if not line or line.startswith(("Name", "Package", "Command")): continue parts = parser(line) if len(parts) >= 2: app_name = parts[0].strip() app_version = parts[1].strip() apps.append({"name": app_name, "version": app_version}) except (subprocess.CalledProcessError, FileNotFoundError): continue return list({app["name"]: app for app in apps}.values()) def main(): print("🔍 正在扫描已安装应用程序...\n") if os.name == "nt": # Windows系统 apps = get_windows_apps() elif os.name == "posix": # Linux/Unix系统 apps = get_linux_apps() else: print("❌ 不支持当前操作系统") return print(f"✅ 共检测到 {len(apps)} 个已安装应用:") for idx, app in enumerate(apps, 1): print(f"{idx}. {app['name']} - 版本: {app['version']}") if __name__ == "__main__": main()
- Windows: Run the script as Administrator to access all registry entries. Green/portable apps that don't write to the registry won't be detected.
- Linux: Manually compiled apps (installed via
make install) aren't tracked by package managers, so they won't show up. The script covers common package managers, but you can add more if you use a niche one. - Duplicates: The script uses a dictionary to deduplicate entries, so you won't see the same app listed multiple times.
内容的提问来源于stack exchange,提问作者mad-eye

