【Python 实用工具】手把手教你用 Python 获取设备硬件信息(跨平台版)
在系统监控、硬件信息展示等场景中,获取设备的详细配置是基础需求。本文将介绍一个基于 Python 的跨平台脚本,能够获取操作系统、CPU、内存、磁盘、网络及 GPU 等信息,并对代码实现进行详细解析。代码兼容 Windows/Linux/macOS,文末附完整代码和使用说明。
一、核心功能与技术栈
脚本通过多个 Python 库和系统工具实现跨平台兼容性,主要功能包括:
- 系统信息:获取操作系统类型、版本、硬件架构等
- CPU 信息:型号、物理核心数、逻辑核心数、实时频率
- 内存 / 磁盘:总量、可用空间、占用率
- 网络信息:主机名、IP 地址、MAC 地址
- GPU 信息:型号、显存、温度、利用率(支持 NVIDIA/AMD/ 集成显卡)
依赖库
platform
:获取系统基础信息psutil
:跨平台硬件监控(CPU / 内存 / 磁盘)socket/uuid
:网络信息获取py3nvml
(可选):NVIDIA 显卡深度信息(需额外安装)
二、代码逐模块解析
1. 系统信息:识别操作系统与版本
system = platform.system()
info['系统'] = system
通过 platform.system()
获取系统类型(Windows/Linux/Darwin),并针对 Windows 做版本友好化处理:
if system == "Windows":
version = platform.version()
info['系统版本'] = get_windows_friendly_name(version) # 转为"Windows 11 23H2"等易读格式
get_windows_friendly_name
函数通过解析版本号构建号(如 22621
对应 Windows 11 23H2),避免原始版本号(如 10.0.22621
)的晦涩。
2. CPU 信息:核心数与型号获取
info['CPU物理核心数'] = psutil.cpu_count(logical=False) # 真实核心数(如8核)
info['CPU逻辑核心数'] = psutil.cpu_count(logical=True) # 超线程线程数(如16线程)
利用 psutil
轻松获取核心数,区分物理核心与逻辑线程。
型号获取分系统处理:
- Windows:读取注册表
HKEY_LOCAL_MACHINE
获取完整型号(如 "AMD Ryzen 7 5800H") - Linux:解析
/proc/cpuinfo
文件中的model name
字段 - macOS:调用
sysctl
命令获取 CPU 品牌字符串(如 "Apple M1")
if system == "Windows":
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0")
cpu_model = winreg.QueryValueEx(key, "ProcessorNameString")[0]
3. 内存与磁盘:使用 psutil 快速获取状态
mem = psutil.virtual_memory()
info['内存总量'] = f"{mem.total / (1024 ** 3):.2f} GB" # 字节转GB,保留两位小数
info['内存使用率'] = f"{mem.percent}%" # 直接获取占用率
磁盘信息同理,通过 psutil.disk_usage('/')
获取系统盘使用情况,支持跨平台路径(Windows 自动识别系统盘,Linux/macOS 使用根目录 /
)。
4. 网络信息:主机名、IP 与 MAC 地址
info['主机名'] = socket.gethostname() # 设备在局域网中的名称(如"r9000p")
info['IP地址'] = socket.gethostbyname(hostname) # 解析IP,失败时返回"未知"
MAC 地址通过 uuid.getnode()
获取整数后格式化为标准 XX:XX:XX
形式,无需调用系统命令。
5. GPU 信息:多层检测策略应对复杂硬件
由于显卡品牌和系统差异,脚本采用三级回退策略:
- 专用库优先(NVIDIA):使用
py3nvml
获取显存、温度、利用率(需pip install py3nvml
)
nvml.nvmlInit()
handle = nvml.nvmlDeviceGetHandleByIndex(0)
temp = nvml.nvmlDeviceGetTemperature(handle, nvml.NVML_TEMPERATURE_GPU)
- 系统命令兜底:
- Windows:
wmic
获取显卡型号 - Linux:
lspci
扫描 PCI 设备 - macOS:
system_profiler
提取显卡芯片型号
- Windows 专属方案:通过
dxdiag
或 WMI 获取基础信息,确保至少返回型号
三、典型输出示例
运行脚本后,控制台将输出类似以下信息
============================== 设备信息 ==============================
系统 : Windows
系统版本 : Windows 11 23H2
CPU型号 : AMD Ryzen 7 5800H with Radeon Graphics
内存总量 : 15.86 GB
磁盘使用率 : 71.7%
显卡型号 : NVIDIA GeForce RTX 3060 Laptop GPU
显存总量 : 6144.00 MiB
显卡温度 : 60°C
四、完整代码
import platform
import psutil
import socket
import uuid
import subprocess
from typing import Dict, Union, Any, Optional
import os
from pathlib import Path
def get_device_info() -> Dict[str, Any]:
"""获取设备信息的主函数。
Returns:
Dict[str, Any]: 包含系统、CPU、内存、磁盘和GPU等信息的字典
"""
info = {}
# 系统信息
system = platform.system()
info['系统'] = system
# 增强Windows版本识别
if system == "Windows":
version = platform.version()
info['系统版本'] = get_windows_friendly_name(version)
info['系统构建号'] = version
else:
info['系统版本'] = platform.version()
info['机器类型'] = platform.machine()
info['处理器架构'] = platform.processor()
# CPU 信息
info['CPU型号'] = get_cpu_model()
info['CPU物理核心数'] = psutil.cpu_count(logical=False) or 0
info['CPU逻辑核心数'] = psutil.cpu_count(logical=True) or 0
# CPU 频率
try:
freq = psutil.cpu_freq()
info['CPU频率'] = f"{freq.current:.2f} MHz" if freq else "未知"
except Exception:
info['CPU频率'] = "未知"
# 内存信息
mem = psutil.virtual_memory()
info['内存总量'] = f"{mem.total / (1024 ** 3):.2f} GB"
info['可用内存'] = f"{mem.available / (1024 ** 3):.2f} GB"
info['内存使用率'] = f"{mem.percent}%"
# 磁盘信息
try:
disk = psutil.disk_usage('/')
info['磁盘总量'] = f"{disk.total / (1024 ** 3):.2f} GB"
info['磁盘已用'] = f"{disk.used / (1024 ** 3):.2f} GB"
info['磁盘可用'] = f"{disk.free / (1024 ** 3):.2f} GB"
info['磁盘使用率'] = f"{disk.percent}%"
except Exception:
info['磁盘总量'] = "未知"
info['磁盘已用'] = "未知"
info['磁盘可用'] = "未知"
info['磁盘使用率'] = "未知"
# 网络信息
info['主机名'] = socket.gethostname()
try:
info['IP地址'] = socket.gethostbyname(socket.gethostname())
except Exception:
info['IP地址'] = "未知"
info['MAC地址'] = ':'.join(("%012X" % uuid.getnode())[i:i+2] for i in range(0, 12, 2))
# GPU 信息
gpu_info = get_gpu_info()
if isinstance(gpu_info, dict):
# 将GPU信息的键名转为中文
gpu_mapping = {
'gpu': '显卡型号',
'gpu_memory_total': '显存总量',
'gpu_memory_used': '显存已用',
'gpu_memory_free': '显存可用',
'gpu_temperature': '显卡温度',
'gpu_utilization': '显卡使用率',
'gpu_driver_version': '显卡驱动版本'
}
for key, value in gpu_info.items():
if key in gpu_mapping:
info[gpu_mapping[key]] = value
else:
info['显卡型号'] = gpu_info
info['显存总量'] = "未知"
info['显存已用'] = "未知"
info['显存可用'] = "未知"
info['显卡温度'] = "未知"
return info
def get_windows_friendly_name(version: str) -> str:
"""获取Windows的友好名称
Args:
version: Windows版本号字符串
Returns:
str: Windows友好名称
"""
# 提取构建号
try:
build_number = int(version.split('.')[-1])
# Windows 11
if build_number >= 22000:
# 尝试获取更具体的版本信息
try:
if build_number >= 22621:
return "Windows 11 23H2"
elif build_number >= 22500:
return "Windows 11 22H2"
else:
return "Windows 11 21H2"
except:
return "Windows 11"
# Windows 10
elif build_number >= 10240:
# 尝试确定具体版本
if build_number >= 19045:
return "Windows 10 22H2"
elif build_number >= 19044:
return "Windows 10 21H2"
elif build_number >= 19043:
return "Windows 10 21H1"
elif build_number >= 19042:
return "Windows 10 20H2"
elif build_number >= 19041:
return "Windows 10 2004"
elif build_number >= 18363:
return "Windows 10 1909"
else:
return f"Windows 10 (构建号: {build_number})"
# Windows 8.1
elif build_number >= 9600:
return "Windows 8.1"
# Windows 8
elif build_number >= 9200:
return "Windows 8"
# Windows 7
elif build_number >= 7600:
return "Windows 7"
# 其他情况
else:
return f"Windows (构建号: {build_number})"
except:
# 如果无法解析版本号,返回原始版本字符串
return version
def get_cpu_model() -> str:
"""获取CPU型号信息。
Returns:
str: CPU型号名称
"""
system = platform.system()
if system == "Windows":
try:
import winreg
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0")
cpu_model, _ = winreg.QueryValueEx(key, "ProcessorNameString")
winreg.CloseKey(key)
return cpu_model
except Exception:
return "未知"
elif system == "Linux":
try:
with open("/proc/cpuinfo", "r") as f:
for line in f:
if line.startswith("model name"):
return line.split(":")[1].strip()
return "未知"
except Exception:
return "未知"
elif system == "Darwin": # macOS
try:
output = subprocess.check_output(["sysctl", "-n", "machdep.cpu.brand_string"],
text=True).strip()
return output
except Exception:
return "未知"
else:
return f"不支持的系统: {system}"
def get_gpu_info() -> Union[Dict[str, str], str]:
"""尝试多种方法获取GPU信息。
Returns:
Union[Dict[str, str], str]: GPU信息字典或描述性错误信息
"""
system = platform.system()
# 方法1: 尝试使用第三方库获取详细信息
gpu_info = _try_get_gpu_with_libraries()
if gpu_info:
return gpu_info
# 方法2: 使用系统命令行工具
gpu_info = _try_get_gpu_with_system_tools(system)
if gpu_info:
return gpu_info
# 方法3: 仅Windows - 使用dxdiag
if system == "Windows":
gpu_info = _try_get_gpu_with_dxdiag()
if gpu_info:
return gpu_info
# 最后尝试使用WMI (仅限Windows)
if system == "Windows":
gpu_info = _try_get_gpu_with_wmi()
if gpu_info:
return gpu_info
return "未能检测到GPU信息"
def _try_get_gpu_with_libraries() -> Optional[Dict[str, str]]:
"""尝试使用专用库获取GPU信息。"""
# 尝试检测NVIDIA GPU (需要py3nvml库)
try:
import py3nvml.py3nvml as nvml
nvml.nvmlInit()
device_count = nvml.nvmlDeviceGetCount()
if device_count > 0:
handle = nvml.nvmlDeviceGetHandleByIndex(0) # 获取第一个GPU
name = nvml.nvmlDeviceGetName(handle)
memory = nvml.nvmlDeviceGetMemoryInfo(handle)
temp = nvml.nvmlDeviceGetTemperature(handle, nvml.NVML_TEMPERATURE_GPU)
utilization = nvml.nvmlDeviceGetUtilizationRates(handle)
nvml.nvmlShutdown()
return {
"gpu": name.decode('utf-8') if isinstance(name, bytes) else name,
"gpu_memory_total": f"{memory.total / (1024**2):.2f} MiB",
"gpu_memory_used": f"{memory.used / (1024**2):.2f} MiB",
"gpu_memory_free": f"{memory.free / (1024**2):.2f} MiB",
"gpu_temperature": f"{temp}°C",
"gpu_utilization": f"{utilization.gpu}%"
}
except (ImportError, Exception):
pass
# 尝试检测AMD GPU (需要pyadl库)
try:
from pyadl import ADLManager
adl = ADLManager()
if adl.get_device_count() > 0:
gpu_name = adl.get_device_name(0) # 获取第一个GPU
return {
"gpu": gpu_name,
"gpu_temperature": f"{adl.get_temp(0)}°C",
"gpu_utilization": f"{adl.get_activity_percentage(0)}%",
"gpu_memory_total": "未知", # pyadl不提供内存信息
"gpu_memory_used": "未知",
"gpu_memory_free": "未知"
}
except (ImportError, Exception):
pass
return None
def _try_get_gpu_with_system_tools(system: str) -> Optional[Dict[str, str]]:
"""使用系统工具获取GPU信息。"""
try:
if system == "Windows":
result = subprocess.run(["wmic", "path", "win32_VideoController", "get", "Name"],
capture_output=True, text=True, check=False)
if result.returncode == 0:
output = result.stdout
gpu_names = [line.strip() for line in output.split("\n") if line.strip() and "Name" not in line]
if gpu_names:
return {"gpu": gpu_names[0]}
elif system == "Linux":
result = subprocess.run(["lspci", "-vnn"], capture_output=True, text=True, check=False)
if result.returncode == 0:
output = result.stdout
gpu_info = [line for line in output.split("\n") if "VGA compatible controller" in line]
if gpu_info:
return {"gpu": gpu_info[0].split(":")[-1].strip()}
elif system == "Darwin": # macOS
result = subprocess.run(["system_profiler", "SPDisplaysDataType"],
capture_output=True, text=True, check=False)
if result.returncode == 0:
output = result.stdout
gpu_info = [line for line in output.split("\n") if "Chipset Model" in line]
if gpu_info:
return {"gpu": gpu_info[0].split(":")[-1].strip()}
except Exception:
pass
return None
def _try_get_gpu_with_dxdiag() -> Optional[Dict[str, str]]:
"""使用dxdiag工具获取GPU信息(仅Windows)。"""
try:
import tempfile
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt')
temp_path = temp_file.name
temp_file.close()
# 运行dxdiag并保存到临时文件
subprocess.run(["dxdiag", "/t", temp_path], check=False)
# 等待文件生成
import time
max_wait = 5 # 最多等待5秒
for _ in range(max_wait):
if os.path.exists(temp_path) and os.path.getsize(temp_path) > 0:
break
time.sleep(1)
if not os.path.exists(temp_path) or os.path.getsize(temp_path) == 0:
return None
# 读取文件内容
gpu_name = "未检测到GPU"
gpu_memory = "未知"
with open(temp_path, 'r', errors='ignore') as f:
content = f.read()
# 寻找GPU信息
display_sections = content.split("---------")
for section in display_sections:
if "显示设备" in section or "Display Devices" in section:
for line in section.split("\n"):
if ":" in line:
key, value = line.split(":", 1)
key = key.strip()
value = value.strip()
if "名称" in key or "Name" in key:
if value and value != "":
gpu_name = value
if "显示内存" in key or "Display Memory" in key:
if value and value != "":
gpu_memory = value
# 删除临时文件
try:
os.unlink(temp_path)
except Exception:
pass
return {
"gpu": gpu_name,
"gpu_memory_total": gpu_memory,
"gpu_memory_used": "未知",
"gpu_memory_free": "未知",
"gpu_temperature": "未知"
}
except Exception:
return None
def _try_get_gpu_with_wmi() -> Optional[Dict[str, str]]:
"""使用WMI获取GPU信息(仅Windows)。"""
try:
import wmi
w = wmi.WMI()
gpu_info = w.Win32_VideoController()[0]
# 获取基本信息
adapter_ram = getattr(gpu_info, 'AdapterRAM', 0)
gpu_data = {
"gpu": gpu_info.Name,
"gpu_driver_version": getattr(gpu_info, "DriverVersion", "未知"),
"gpu_memory_total": f"{int(adapter_ram) / (1024**3):.2f} GB" if adapter_ram else "未知",
"gpu_memory_used": "未知",
"gpu_memory_free": "未知",
"gpu_temperature": "未知"
}
# 对于NVIDIA GPU,尝试使用更专业的方法获取
if "NVIDIA" in gpu_info.Name:
try:
# 尝试使用 nvidia-smi 获取更详细信息
nvidia_smi = subprocess.run(
["nvidia-smi", "--query-gpu=memory.total,memory.used,memory.free,temperature.gpu",
"--format=csv,noheader,nounits"],
capture_output=True, text=True, check=False
)
if nvidia_smi.returncode == 0:
values = nvidia_smi.stdout.strip().split(", ")
if len(values) >= 4:
gpu_data["gpu_memory_total"] = f"{float(values[0]):.2f} MiB"
gpu_data["gpu_memory_used"] = f"{float(values[1]):.2f} MiB"
gpu_data["gpu_memory_free"] = f"{float(values[2]):.2f} MiB"
gpu_data["gpu_temperature"] = f"{values[3]}°C"
except Exception:
pass
return gpu_data
except Exception:
return None
def print_device_info(info: Dict[str, Any]) -> None:
"""打印设备信息到控制台。
Args:
info (Dict[str, Any]): 设备信息字典
"""
print("=" * 40, "设备信息", "=" * 40)
for key, value in info.items():
print(f"{key:<20}: {value}")
if __name__ == "__main__":
device_info = get_device_info()
print_device_info(device_info)
评论区