Ответ 1
Как использовать MAC-адрес как уникальный идентификатор?
Обсуждение здесь Получение MAC-адреса с устройств с использованием Python показывает, как получить MAC-адрес
Я хотел бы получить идентификатор, уникальный для компьютера с Python в Windows и Linux. Это может быть идентификатор CPU, серийный номер материнской платы... или что-то еще.
Я посмотрел несколько модулей (pycpuid, psi,...) без везения.
Любая идея о том, как это сделать?
Как использовать MAC-адрес как уникальный идентификатор?
Обсуждение здесь Получение MAC-адреса с устройств с использованием Python показывает, как получить MAC-адрес
Кажется, нет прямого "питонного" способа сделать это. На современном оборудовании для ПК обычно есть UUID, хранящийся в BIOS - в Linux есть утилита командной строки dmidecode
, которая может это прочитать; пример с моего рабочего стола:
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-адресами заключается в том, что обычно вы можете легко изменять их программно (по крайней мере, если вы запустите ОС в виртуальной машине)
В Windows вы можете использовать этот API С#.
для Windows вам нужен DmiDecode для Windows (ссылка):
subprocess.Popen('dmidecode.exe -s system-uuid'.split())
для Linux (не root):
subprocess.Popen('hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.uuid'.split())
Для python3.6 и windows должен быть использован декодировать
>>> import subprocess
... current_machine_id = subprocess.check_output('wmic csproduct get uuid').decode().split('\n')[1].strip()
... print(current_machine_id)
Или, если вы не хотите использовать подпроцесс (медленно), используйте ctypes. Это для Linux не root.
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_
Вы можете использовать это как:
get_uuid = HardwareUuid()
print get_uuid()
Я не думаю, что есть надежная кросс-платформа, способ сделать это. Я знаю одно сетевое устройство, которое меняет свой MAC-адрес как форму сообщения об ошибках аппаратного обеспечения, и есть миллион других способов, которые это может привести к сбою.
Единственное надежное решение для вашего приложения - назначить уникальный ключ для каждой машины. Да, это может быть подделано, но вам не нужно беспокоиться об этом, полностью разбираясь. Если вас беспокоит спуфинг, вы можете применить какую-то эвристику (например, изменение адреса mac), чтобы попытаться определить, был ли перемещен ключ.
ОБНОВЛЕНИЕ: Вы можете использовать бактериальную отпечатку пальца.
Вызовите один из них в оболочке или через канал в Python, чтобы получить серийный номер оборудования компьютеров Apple, работающих под управлением OS X> = 10,5:
/usr/sbin/system_profiler SPHardwareDataType | fgrep 'Serial' | awk '{print $NF}'
или
ioreg -l | awk '/IOPlatformSerialNumber/ { print $4 }' | sed s/\"//g
Кстати, MAC-адреса не очень хорошая идея: в машине может быть> 1 сетевая карта, а MAC-адреса могут быть поддельными.
Забавно! Но uuid.getnode возвращает то же значение, что и dmidecode.exe.
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')
UUID - универсальный уникальный идентификатор
[RFC 4122] Универсальное имя идентификатора (UUID) URN Namespace
Я нашел что-то еще, что я использую. Mac для Linux, MachineGuid для Windows и есть что-то для Mac.
Подробнее здесь: http://www.serialsense.com/blog/2011/02/generating-unique-machine-ids/
Это должно работать с окнами:
import subprocess
current_machine_id = subprocess.check_output('wmic csproduct get uuid').split('\n')[1].strip()
Ответ 2019 (для Windows):
from typing import Optional
import re
import subprocess
import uuid
def get_windows_uuid() -> Optional[uuid.UUID]:
try:
# Ask Windows for the device permanent UUID. Throws if command missing/fails.
txt = subprocess.check_output("wmic csproduct get uuid").decode()
# Attempt to extract the UUID from the command result.
match = re.search(r"\bUUID\b[\s\r\n]+([^\s\r\n]+)", 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-разрядный). целое число, шестнадцатеричная строка и т.д.).
Удачи!