关于硬件:在Windows和Linux上使用Python获取唯一的计算机ID

Get a unique computer ID in Python on windows and linux

我想获得Windows和Linux上使用Python的计算机唯一的ID。 可能是CPU ID,主板序列号或其他。

我看了几个运气不好的模块(pycpuid,psi,...)。

关于如何做到这一点的任何想法?


似乎没有直接的" python"方式可以做到这一点。在现代PC硬件上,通常在BIOS中存储有一个UUID-在Linux上,有一个命令行实用程序dmidecode可以读取此信息。我的桌面上的示例:

1
2
3
4
5
6
7
8
9
System Information
        Manufacturer: Dell Inc.
        Product Name: OptiPlex 755                
        Version: Not Specified
        Serial Number: 5Y8YF3J
        UUID: 44454C4C-5900-1038-8059-B5C04F46334A
        Wake-up Type: Power Switch
        SKU Number: Not Specified
        Family: Not Specified

MAC地址的问题在于,通常您可以轻松地以编程方式更改它们(至少如果在VM中运行操作系统)

在Windows上,您可以使用此C API


对于Windows,您需要Windows的DmiDecode(链接):

1
subprocess.Popen('dmidecode.exe -s system-uuid'.split())

对于Linux(非root用户):

1
subprocess.Popen('hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.uuid'.split())


对于python3.6和Windows
必须使用解码

1
2
3
4
>>> import subprocess
... current_machine_id = subprocess.check_output('wmic csproduct get uuid').decode().split('\
'
)[1].strip()
... print(current_machine_id)


滑稽!
但是uuid.getnode返回的值与dmidecode.exe相同。

1
2
3
4
5
6
7
8
subprocess.Popen('dmidecode.exe -s system-uuid'.split())

00000000-0000-0000-0000-001FD088565A

import uuid    
uuid.UUID(int=uuid.getnode())

UUID('00000000-0000-0000-0000-001fd088565a')


在外壳中或通过Python中的管道调用其中之一,以获取运行OS X> = 10.5的Apple计算机的硬件序列号:

/usr/sbin/system_profiler SPHardwareDataType | fgrep 'Serial' | awk '{print $NF}'

要么

ioreg -l | awk '/IOPlatformSerialNumber/ { print $4 }' | sed s/\\"//g

顺便说一句:MAC地址不是一个好主意:一台机器中可以有1个以上的网卡,并且MAC地址可以被欺骗。


或者,如果您不想使用子进程,(很慢)请使用ctypes。这适用于Linux非root用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import ctypes
from ctypes.util import find_library
from ctypes import Structure

class DBusError(Structure):
    _fields_ = [("name", ctypes.c_char_p),
                ("message", ctypes.c_char_p),
                ("dummy1", ctypes.c_int),
                ("dummy2", ctypes.c_int),
                ("dummy3", ctypes.c_int),
                ("dummy4", ctypes.c_int),
                ("dummy5", ctypes.c_int),
                ("padding1", ctypes.c_void_p),]


class HardwareUuid(object):

    def __init__(self, dbus_error=DBusError):
        self._hal = ctypes.cdll.LoadLibrary(find_library('hal'))
        self._ctx = self._hal.libhal_ctx_new()
        self._dbus_error = dbus_error()
        self._hal.dbus_error_init(ctypes.byref(self._dbus_error))
        self._conn = self._hal.dbus_bus_get(ctypes.c_int(1),
                                            ctypes.byref(self._dbus_error))
        self._hal.libhal_ctx_set_dbus_connection(self._ctx, self._conn)
        self._uuid_ = None

    def __call__(self):
        return self._uuid

    @property
    def _uuid(self):
        if not self._uuid_:
            udi = ctypes.c_char_p("/org/freedesktop/Hal/devices/computer")
            key = ctypes.c_char_p("system.hardware.uuid")
            self._hal.libhal_device_get_property_string.restype = \\
                                                            ctypes.c_char_p
            self._uuid_ = self._hal.libhal_device_get_property_string(
                                self._ctx, udi, key, self._dbus_error)
        return self._uuid_

您可以这样使用:

1
2
get_uuid = HardwareUuid()
print get_uuid()


我认为没有可靠的跨平台方法可以做到这一点。我知道有一种网络设备会更改其MAC地址,这是一种硬件错误报告的形式,还有百万种其他方法可能会失败。

唯一可靠的解决方案是为您的应用程序为每台计算机分配唯一的密钥。是的,它可以被欺骗,但是您不必担心它会完全损坏。如果您担心欺骗,则可以应用某种启发式方法(例如更改mac地址)来尝试确定密钥是否已移动。

更新:您可以使用细菌指纹识别。


在Windows上应该可以使用:

1
2
3
import subprocess
current_machine_id = subprocess.check_output('wmic csproduct get uuid').split('\
'
)[1].strip()


UUID-通用唯一标识符

Python uuid模块

[RFC 4122]通用唯一标识符(UUID)URN命名空间


2019年答案(对于Windows):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from typing import Optional
import re
import subprocess
import uuid

def get_windows_uuid() -> Optional[uuid.UUID]:
    try:
        # Ask Windows for the device's permanent UUID. Throws if command missing/fails.
        txt = subprocess.check_output("wmic csproduct get uuid").decode()

        # Attempt to extract the UUID from the command's result.
        match = re.search(r"\\bUUID\\b[\\s\
\
]+([^\\s\
\
]+)"
, txt)
        if match is not None:
            txt = match.group(1)
            if txt is not None:
                # Remove the surrounding whitespace (newlines, space, etc)
                # and useless dashes etc, by only keeping hex (0-9 A-F) chars.
                txt = re.sub(r"[^0-9A-Fa-f]+","", txt)

                # Ensure we have exactly 32 characters (16 bytes).
                if len(txt) == 32:
                    return uuid.UUID(txt)
    except:
        pass # Silence subprocess exception.

    return None

print(get_windows_uuid())

使用Windows API获取计算机的永久UUID,然后处理字符串以确保它是有效的UUID,最后返回一个Python对象(https://docs.python.org/3/library/uuid.html),这为您提供了方便使用数据的方式(例如128位整数,十六进制字符串等)。

祝好运!

PS:可以用直接为Win32_ComputerSystemProduct API(这是wmic内部使用的)调用Windows内核/ DLL的ctypes替换子进程调用。但是随后您必须非常小心,并确保在所有系统上都正确调用它。对我而言,基于wmic的功能更安全,这就是我所需要的。它会进行严格的验证并产生正确的结果。而且,如果wmic输出错误或命令丢失,我们的函数将返回None,让您以所需的任何方式进行处理(例如生成随机UUID并将其保存在应用程序的配置文件中)。


我发现了我正在使用的其他东西。 linux的Mac地址,windows的MachineGuid,还有mac的东西。

详情请见:
http://www.serialsense.com/blog/2011/02/generating-unique-machine-ids/


如何使用MAC地址作为唯一ID?

此处的讨论使用Python从设备获取MAC地址显示了如何获取MAC地址