目 录CONTENT

文章目录

Python-获取设备信息

~梓
2025-05-09 / 0 评论 / 0 点赞 / 18 阅读 / 0 字
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

【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 信息:多层检测策略应对复杂硬件

由于显卡品牌和系统差异,脚本采用三级回退策略:

  1. 专用库优先(NVIDIA):使用 py3nvml获取显存、温度、利用率(需 pip install py3nvml
nvml.nvmlInit()  
handle = nvml.nvmlDeviceGetHandleByIndex(0)  
temp = nvml.nvmlDeviceGetTemperature(handle, nvml.NVML_TEMPERATURE_GPU)  
  1. 系统命令兜底
  • Windows:wmic获取显卡型号
  • Linux:lspci扫描 PCI 设备
  • macOS:system_profiler提取显卡芯片型号
  1. 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)
0

评论区