Получение MAC-адреса

Мне нужен кросс-платформенный метод определения MAC-адреса компьютера во время выполнения. Для Windows можно использовать модуль wmi, и единственный метод в Linux, который я смог найти, - это запустить ifconfig и запустить регулярное выражение на его выходе. Мне не нравится использовать пакет, который работает только в одной ОС, а анализ вывода другой программы не кажется очень элегантным, не говоря уже о подверженности ошибкам.

Кто-нибудь знает метод кросс-платформенного (windows и linux) для получения MAC-адреса? Если нет, знает ли кто-нибудь более элегантные методы, чем те, которые я перечислил выше?

Здесь есть много потенциально полезных ответов! Как я могу получить IP-адрес eth0 в Python?

uhoh 12.04.2018 01:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
118
1
157 546
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

netifaces - хороший модуль для получения MAC-адреса (и других адресов). Он кроссплатформенный и имеет немного больше смысла, чем использование socket или uuid.

>>> import netifaces
>>> netifaces.interfaces()
['lo', 'eth0', 'tun2']

>>> netifaces.ifaddresses('eth0')[netifaces.AF_LINK]
[{'addr': '08:00:27:50:f2:51', 'broadcast': 'ff:ff:ff:ff:ff:ff'}]

Использовал его лично, требует определенной установки / компиляции в каждой системе, но работает хорошо.

Aatch 20.06.2011 21:10

Я не знаю единого способа, но вот кое-что, что может вам пригодиться:

http://www.codeguru.com/Cpp/I-N/network/networkinformation/article.php/c5451

Что я бы сделал в этом случае, так это обернуло бы их в функцию, и в зависимости от ОС она запустила бы правильную команду, проанализировала по мере необходимости и вернула только MAC-адрес, отформатированный так, как вы хотите. Конечно, все то же самое, за исключением того, что вам нужно сделать это только один раз, и это выглядит чище по сравнению с основным кодом.

Ответ принят как подходящий

Python 2.5 включает реализацию uuid, которой (по крайней мере, в одной версии) нужен MAC-адрес. Вы можете легко импортировать функцию поиска Mac в свой собственный код:

from uuid import getnode as get_mac
mac = get_mac()

Возвращаемое значение - это 48-битный целочисленный MAC-адрес.

Я просто попробовал это на коробке с Windows, и он отлично работает ... за исключением того, что ноутбук, на котором я его пробовал, имеет 2 сетевых адаптера (один беспроводной), и нет способа определить, какой MAC он вернул. Небольшое предупреждение, если вы хотите использовать этот код.

technomalogical 01.10.2008 23:55

Это особенность перечислителя устройств Windows, какой бы метод вы ни использовали для получения адреса - вы должны быть осторожны, используя его в качестве уникального идентификатора.

Martin Beckett 02.10.2008 02:12

Просто предупреждение: если вы посмотрите документацию getnode, там написано, что он вернет случайное длинное число, если не сможет обнаружить Mac: «Если все попытки получить аппаратный адрес терпят неудачу, мы выбираем случайное 48-битное число с его восьмым. бит установлен в 1, как рекомендовано в RFC 4122. " Так что проверьте восьмой бит!

deinonychusaur 01.02.2013 15:27

hex(mac), чтобы получить знакомый шестнадцатеричный формат Mac

screenshot345 23.03.2014 21:29

Или ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2)) для MAC верхнего регистра с каждым байтом, разделенным двоеточием.

tomlogic 10.11.2014 20:21

getnode () возвращает что-то новое каждый раз, когда я перезагружаю свой ноутбук с Windows 7.

nu everest 16.11.2014 00:52

@deinonychusaur У меня есть действующий MAC-адрес, где младший бит первого октекта равен 1. Кажется, этого недостаточно для проверки возвращаемого значения. Однако в своем ответе ниже mhawke предлагает решение, которое может сработать.

chris 05.06.2015 20:53

Или ':'.join((itertools.starmap(operator.add, zip(*([iter("%012X" % mac)] * 2))))), альтернативный способ сделать это @tomlogic

Bryce Guinta 28.10.2016 22:13

это укусило меня в задницу - во встроенной системе он возвращал случайное значение, если разъем Ethernet не подключен, однако чтение / sys / class / net / eth0 / address (или анализ вывода ifconfig) работает либо с подключением, либо без

Richard Aplin 10.02.2017 11:09

@tomlogic - отлично работает !! Очень загадочный, но приятный лайнер, который делает именно то, что мне нужно. ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))

svenyonson 03.03.2018 06:14

Для Linux вы можете получить MAC-адрес с помощью SIOCGIFHWADDR ioctl.

struct ifreq    ifr;
uint8_t         macaddr[6];

if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
    return -1;

strcpy(ifr.ifr_name, "eth0");

if (ioctl(s, SIOCGIFHWADDR, (void *)&ifr) == 0) {
    if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
        memcpy(macaddr, ifr.ifr_hwaddr.sa_data, 6);
        return 0;
... etc ...

Вы отметили вопрос "питон". Я не знаю существующего модуля Python для получения этой информации. Вы можете использовать ctypes для прямого вызова ioctl.

-1 Ему нужен раствор на питоне, поэтому вы идете и даете ему тот же раствор С срыгиванием, разложенный по всей сети.

Aatch 07.06.2011 09:00

Обратите внимание, что вы можете создать свою собственную кроссплатформенную библиотеку на Python, используя условный импорт. например

import platform
if platform.system() == 'Linux':
  import LinuxMac
  mac_address = LinuxMac.get_mac_address()
elif platform.system() == 'Windows':
  # etc

Это позволит вам использовать системные вызовы os.system или библиотеки для конкретной платформы.

это не совсем ответ - просто комментарий

Stefano 04.02.2019 15:08

Еще одна вещь, на которую вы должны обратить внимание, заключается в том, что uuid.getnode() может подделать адрес MAC, возвращая случайное 48-битное число, которое может быть не тем, что вы ожидаете. Кроме того, нет явных указаний на то, что MAC-адрес был подделан, но вы можете обнаружить его, дважды позвонив в getnode() и проверив, изменится ли результат. Если оба вызова возвращают одно и то же значение, у вас есть MAC-адрес, в противном случае вы получаете поддельный адрес.

>>> print uuid.getnode.__doc__
Get the hardware address as a 48-bit positive integer.

    The first time this runs, it may launch a separate program, which could
    be quite slow.  If all attempts to obtain the hardware address fail, we
    choose a random 48-bit number with its eighth bit set to 1 as recommended
    in RFC 4122.

Не то чтобы значение 8-го было 1 именно потому, что оно не может использоваться сетевой картой. Достаточно просто проверить этот бит, чтобы определить, является ли адрес подделкой.

Frédéric Grosshans 09.07.2012 17:10

Проверка выполняется с помощью: if (mac >> 40)% 2: raise OSError, "Кажется, в системе нет действующего MAC".

Frédéric Grosshans 09.07.2012 17:26

Решение этой проблемы на чистом питоне под Linux для получения MAC для определенного локального интерфейса, первоначально опубликованное как комментарий vishnubob и улучшенное Беном Макки в этот рецепт активного состояния

#!/usr/bin/python

import fcntl, socket, struct

def getHwAddr(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))
    return ':'.join(['%02x' % ord(char) for char in info[18:24]])

print getHwAddr('eth0')

Это код, совместимый с Python 3:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import fcntl
import socket
import struct


def getHwAddr(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', bytes(ifname, 'utf-8')[:15]))
    return ':'.join('%02x' % b for b in info[18:24])


def main():
    print(getHwAddr('enp0s8'))


if __name__ == "__main__":
    main()

Для Linux позвольте мне представить сценарий оболочки, который покажет MAC-адрес и позволит его изменить (анализ MAC).

 ifconfig eth0 | grep HWaddr |cut -dH -f2|cut -d\  -f2
 00:26:6c:df:c3:95

Вырезать аргументы можно (я не эксперт) попробуйте:

ifconfig etho | grep HWaddr
eth0      Link encap:Ethernet  HWaddr 00:26:6c:df:c3:95  

Чтобы изменить MAC, мы можем сделать:

ifconfig eth0 down
ifconfig eth0 hw ether 00:80:48:BA:d1:30
ifconfig eth0 up

изменит MAC-адрес на 00: 80: 48: BA: d1: 30 (временно, вернется к фактическому при перезагрузке).

Это как-то связано с вопросом?

bot47 08.04.2016 18:44

Используя мой ответ отсюда: https://stackoverflow.com/a/18031868/2362361

Было бы важно знать, для какого места вы хотите использовать MAC, поскольку многие из них могут существовать (bluetooth, несколько сетевых адаптеров и т. д.).

Это работает, когда вы знаете IP-адрес iface, для которого вам нужен MAC, используя netifaces (доступный в PyPI):

import netifaces as nif
def mac_for_ip(ip):
    'Returns a list of MACs for interfaces that have given IP, returns None if not found'
    for i in nif.interfaces():
        addrs = nif.ifaddresses(i)
        try:
            if_mac = addrs[nif.AF_LINK][0]['addr']
            if_ip = addrs[nif.AF_INET][0]['addr']
        except IndexError, KeyError: #ignore ifaces that dont have MAC or IP
            if_mac = if_ip = None
        if if_ip == ip:
            return if_mac
    return None

Тестирование:

>>> mac_for_ip('169.254.90.191')
'2c:41:38:0a:94:8b'

Иногда у нас есть более одного сетевого интерфейса.

Простой способ узнать MAC-адрес определенного интерфейса:

def getmac(interface):

  try:
    mac = open('/sys/class/net/'+interface+'/address').readline()
  except:
    mac = "00:00:00:00:00:00"

  return mac[0:17]

вызвать метод просто

myMAC = getmac("wlan0")

Не очень полезно для OS X или Windows. : |

RandomInsano 25.08.2017 19:21

Идеально подходит для писи!

MikeT 23.10.2018 23:19

Вы можете сделать это с помощью кроссплатформенного psutil:

import psutil
nics = psutil.net_if_addrs()
print [j.address for j in nics[i] for i in nics if i! = "lo" and j.family==17]

import socket, затем [addr.address for n in nics for addr in nics[n] if n == 'enp4s0' and addr.family == socket.AF_PACKET] приводит к ['ab:cd:ef:01:02:03']

Donn Lee 14.11.2019 02:33

Для этого подойдет кроссплатформенный пакет Getmac, если вы не против взять на себя зависимость. Он работает с Python 2.7+ и 3.4+. Он будет пробовать много разных методов, пока не получит адрес или не вернет None.

from getmac import get_mac_address
eth_mac = get_mac_address(interface = "eth0")
win_mac = get_mac_address(interface = "Ethernet 3")
ip_mac = get_mac_address(ip = "192.168.0.1")
ip6_mac = get_mac_address(ip6 = "::1")
host_mac = get_mac_address(hostname = "localhost")
updated_mac = get_mac_address(ip = "10.0.0.1", network_request=True)

Отказ от ответственности: я являюсь автором пакета.

Обновление (14 января 2019 г.): теперь пакет поддерживает только Python 2.7+ и 3.4+. Вы все равно можете использовать старую версию пакета, если вам нужно работать со старым Python (2.5, 2.6, 3.2, 3.3).

В качестве альтернативы,

import uuid
mac_id=(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)

Чтобы получить MAC-адрес интерфейса eth0,

import psutil

nics = psutil.net_if_addrs()['eth0']

for interface in nics:
   if interface.family == 17:
      print(interface.address)

Другие вопросы по теме