1. 基础实现(常用但有局限)
在 python 中,我们通常使用 uuid 和 socket 库来快速获取设备网络标识。
import uuid
import socket
# 获取 mac 地址 (基于 getnode)
mac = uuid.uuid(int=uuid.getnode()).hex[-12:].upper()
# 获取主机名与 ip
hostname = socket.getfqdn(socket.gethostname())
ip_addr = socket.gethostbyname(hostname)
print(f"mac: {mac}")
print(f"host: {hostname}")
print(f"ip: {ip_addr}")
2. 核心问题:为什么 mac 地址会变化?
在安装了 vmware 或 virtualbox 等虚拟机软件后,原本稳定的脚本可能会输出不同的 mac 地址。原因如下:
虚拟网卡的干扰
uuid.getnode() 的原理是获取硬件地址。安装虚拟机后,系统会增加多个虚拟网卡(如 vmnet1, vmnet8)。
- 多网卡竞争:脚本可能会随机抓取到虚拟网卡的 mac 地址,而非物理网卡(wifi/以太网)的地址。
- 优先级变动:当物理网卡断开(如拔掉网线)时,系统可能会将虚拟网卡作为默认接口返回。
随机地址回退机制
根据 rfc 4122 协议,如果 uuid.getnode() 无法获取到真实硬件地址,它会随机生成一个 48 位的值。
识别方法:检查 mac 地址的第一个字节。如果其最低有效位为 1(即第二个字符为 1, 3, 5, 7, 9, b, d, f 之一),说明这是一个随机地址。
3. 更稳定的替代方案:硬件 uuid
如果目的是为了唯一识别设备(如软件授权、指纹识别),建议获取 windows 主板的 uuid,这不会受网卡变动或虚拟机的影响。
推荐方案 (python 调用 wmic)
import subprocess
def get_windows_uuid():
try:
# 执行 wmic 命令获取主板唯一标识
cmd = 'wmic path win32_computersystemproduct get uuid'
uuid_str = subprocess.check_output(cmd, shell=true).decode().split('\n')[1].strip()
return uuid_str
except exception as e:
return f"error: {e}"
print(f"设备硬件 uuid: {get_windows_uuid()}")
4. 总结与建议
| 标识符 | 稳定性 | 适用场景 | 风险 |
|---|---|---|---|
| mac 地址 | 一般 | 网络通信、局域网识别 | 易受虚拟机、多网卡、随机化影响 |
| 主机名 | 低 | 内部网络标识 | 用户可随时更改 |
| 硬件 uuid | 极高 | 软件授权、设备指纹 | 需系统权限(通常 cmd 即可) |
笔记提示:
- 在 windows 上运行 python 脚本时,确保已将 python 添加至系统变量
path。 - 如果必须获取物理网卡的 mac,建议使用
psutil库遍历所有网卡并过滤掉包含 "vmware" 或 "virtual" 字样的接口。
5.知识扩展
在 windows 上,获取设备信息最高效的方式是使用 wmi,它能直接访问系统底层的硬件和软件配置。同时,python 的 platform 和 psutil 模块可以作为补充,获取一些基础的系统信息。
下面是一个结构化对比,帮助你快速定位最适合的方法:
主要实现方法对比
| 方法/工具 | 核心原理 | 主要优势 | 潜在限制 | 使用建议 |
|---|---|---|---|---|
| wmi (wmi库) | 通过封装好的 api 访问 windows 原生管理接口。 | 功能最强大,能获取几乎所有系统信息(软件/硬件/配置)。 | 需要安装第三方库。 | 首选,用于获取cpu、主板、硬盘等底层硬件信息。 |
| win32 api (pywin32库) | 直接调用 windows api,交互层级更低。 | 灵活,能实现一些 wmi 不便或无法完成的操作。 | 安装相对复杂,需要pywin32库。 | 高级或特定场景的补充。 |
| 系统组件 (platform模块) | python 内置,跨平台,无需安装。 | 无额外依赖,代码简单。 | 功能有限,主要用于操作系统版本、计算机名、处理器架构等基础信息。 | 获取通用系统信息,或用于跨平台代码中判断操作系统类型。 |
| subprocess + wmic | 调用 windows 命令行工具 wmic,解析其输出。 | 零额外依赖(除 subprocess)。 | 输出为文本,需要解析,且 wmic 可能在未来的 windows 版本中被弃用。 | 需要基本的系统信息,但不能或不想安装 wmi 库的轻量级场景。 |
| 跨平台库 (psutil等) | 第三方库,提供跨平台的系统信息获取功能。 | 跨平台(windows/linux/macos),api 统一,获取实时数据能力强。 | 可能获取不到某些特定硬件的底层序列号。 | 需要监控cpu、内存、磁盘、网络等实时资源时作为重要补充。 |
详细代码示例及解析
准备工作:安装依赖库
对于非 python 内置的模块,你需要先进行安装。建议使用 pip 在命令行中进行安装。
# 建议使用 python -m pip 来确保安装到正确的 python 环境 python -m pip install wmi pywin32 psutil
下面是两种主流的实现方式及核心代码示例。
方式一:使用 wmi 模块(获取cpu、主板、硬盘信息)
这是获取 windows 硬件信息最常用、最强大的方法。
import wmi
try:
# 初始化wmi客户端
c = wmi.wmi()
except wmi.x_wmi as e:
print(f"初始化wmi失败: {e}")
exit()
# 1. 获取cpu信息
print("\n[cpu信息]")
for cpu in c.win32_processor():
# .caption 或 .name 通常包含cpu的完整型号
print(f" 型号: {cpu.name.strip()}")
print(f" 核心数: {cpu.numberofcores}")
print(f" 线程数: {cpu.numberoflogicalprocessors}")
# 2. 获取主板信息
print("\n[主板信息]")
for board in c.win32_baseboard():
# .product 通常是主板的型号
print(f" 型号: {board.product}")
# .manufacturer 是制造商
print(f" 制造商: {board.manufacturer}")
# 3. 获取硬盘信息
print("\n[硬盘信息]")
for disk in c.win32_diskdrive():
# .model 是硬盘型号,.serialnumber 是唯一的序列号
print(f" 型号: {disk.model}")
print(f" 序列号: {disk.serialnumber}")
print(f" 大小: {int(disk.size) // (1024**3)} gb")代码解析:
c = wmi.wmi()这条语句建立与 windows 管理规范的连接,是后续所有查询的基础。win32_processor,win32_baseboard,win32_diskdrive是 wmi 中用于查询cpu、主板和硬盘信息的类。- 你可以通过修改类名来获取其他硬件信息,例如
win32_physicalmemory可以查询内存条信息。
方式二:结合 platform 和 psutil 获取系统概况
这两个库主要用于获取系统概要信息和系统级的运行状态,是跨平台信息获取的得力助手。
import psutil
import platform
print("[操作系统信息]")
# platform.system() 获取操作系统名称,如 'windows', 'linux'[reference:12]
print(f" 系统: {platform.system()}")
# platform.release() 获取操作系统的主版本号[reference:13]
print(f" 版本: {platform.release()}")
# platform.processor() 获取处理器的信息字符串
print(f" 处理器标识: {platform.processor()}")
print(f" 计算机名: {platform.node()}")
print(f" 系统架构: {platform.machine()}")
print("\n[系统运行状态]")
# psutil.virtual_memory().total 获取系统总内存,单位是字节,需要转换为合适的单位。
total_memory = psutil.virtual_memory().total
print(f" 总内存: {total_memory // (1024**3)} gb")
# psutil.disk_usage('/') 获取根目录的磁盘使用情况。你可以改变路径来查看其他盘符。
disk = psutil.disk_usage('/')
print(f" 磁盘 (c:): 总计 {disk.total // (1024**3)}gb, 已用 {disk.used // (1024**3)}gb")关键点:
platform模块的相关函数是获取跨平台系统信息的基础。psutil在获取动态系统数据时非常强大,例如psutil.virtual_memory()和psutil.disk_usage()能提供实时的内存和磁盘使用情况。
方式三:使用 uuid 模块生成唯一设备标识符
这个技术与前两种不同,它不是为了获取硬件清单,而是为了生成一个相对稳定的设备唯一码,常用于软件授权等场景。
import uuid
# 获取计算机的mac地址并生成一个uuid[reference:16]
node_uuid = uuid.uuid(int=uuid.getnode())
# 取uuid的后12位作为机器码
machine_code = node_uuid.hex[-12:]
print(f"\n[生成的机器码]")
print(f" 唯一id: {machine_code}")核心要点:这种方法依赖mac地址,如果网卡变更或mac地址被修改,这个id也会随之改变。此外,也可以调用系统工具(如 wmic csproduct get uuid)获取更稳定的主板uuid。
注意事项与安全警示
在编写代码时,做好错误处理和权限管理,能让你的程序更健壮。
- 管理员权限:访问某些硬件信息(如硬盘序列号)可能需要程序以管理员权限运行,否则可能会返回
none或抛出异常。 - 虚拟机环境:在虚拟机中,获取到的硬件信息(特别是序列号)可能是虚拟化软件模拟的固定值,多台机器可能相同。
- 错误处理:务必使用
try...except语句块来处理wmi初始化失败、注册表键值找不到等异常情况。 - 隐私合规:在收集和传输任何硬件信息前,请务必告知用户并获得其同意,遵守相关的隐私法规。
- 兼容性预案:
wmic命令行工具可能在未来的 windows 版本中被移除。如有需要,你可以将代码中的wmic调用封装成函数,以便将来平滑迁移到get-wmiobject等 powershell 命令。
你对哪部分的实现,或是针对特定硬件的查询更感兴趣呢?我可以进一步为你提供更详细的代码示例。
到此这篇关于python实现获取windows设备信息的文章就介绍到这了,更多相关python获取windows设备信息内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论