获取MAC地址

137

我需要一种跨平台的方法来在运行时确定计算机的MAC地址。对于Windows系统可以使用'wmi'模块,而在Linux系统下我只能找到运行ifconfig并在其输出上运行正则表达式的方法。我不喜欢使用只适用于一个操作系统的软件包,并且解析另一个程序的输出似乎并不优雅,更不用说容易出错了。

有人知道一种跨平台的方法(适用于Windows和Linux系统)来获取MAC地址吗?如果没有,是否有任何比我上面列出的方法更优雅的方法呢?


这里有许多可能有帮助的答案!如何在Python中获取eth0的IP地址? - uhoh
注意:接受的答案是错误的:在同一台计算机上的两个不同进程中同时运行,会导致得到2个不同的值。 - Sławomir Lenart
17个回答

189

Python 2.5 包含一个 uuid 实现,但至少有一个版本需要 mac 地址。你可以轻松地将查找 mac 地址的函数导入到自己的代码中:

from uuid import getnode as get_mac
mac = get_mac()

返回值是MAC地址的48位整数。


28
我刚在一个 Windows 设备上尝试了这个代码,效果很好...但是我尝试的笔记本电脑有两个网卡(一个是无线的),无法确定它返回的是哪个网卡的 MAC 地址。如果你想使用这段代码,需要注意这一点。 - technomalogical
27
警告:如果您查看 getnode 文档,它表示如果无法检测到 MAC 地址,它将返回一个随机的长整形数:"如果所有获取硬件地址的尝试都失败了,我们选择一个随机的 48 位数,并将其第八个比特设置为 1,正如 RFC 4122 建议的那样。" 因此请检查第八个比特! - deinonychusaur
30
使用hex(mac)可以获得MAC地址的熟悉十六进制格式。 - screenshot345
52
将一个大写MAC地址转换为以冒号分隔的每个字节的形式,可以使用以下代码:':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2)) - tomlogic
9
每次我重新启动我的Windows 7笔记本电脑时,getnode()返回的结果都不同。 - nu everest
显示剩余5条评论

97

这个问题在Linux下获取特定本地接口的MAC地址的纯Python解决方案,最初是由vishnubob在Ben Mackey的此Activestate recipe中作为评论发布的,并得到改进。

#!/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()

1
美丽,运行得很好! - Sean McCarthy

42

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'}]


1
个人使用过,需要在每个系统上进行特定的安装/编译,但效果很好。 - Aatch

29

有时我们会有多个网络接口。

找出特定接口的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")

6
在OS X或Windows上并不是非常有用。 :| - RandomInsano
3
适合双鱼座! - MikeT
return mac.strip() 可能更容易去掉换行符 ;-) - Pedro A. Aranda

22

需要注意的一点是uuid.getnode()函数可以通过返回一个随机的48位数字来伪造MAC地址,这可能不是你所期望的结果。此外,并没有明确指示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
18
检查只需执行以下代码: if (mac >> 40) % 2: raise OSError,"系统似乎没有有效的MAC地址" - Frédéric Grosshans

9

使用我在这里的答案:https://stackoverflow.com/a/18031868/2362361

重要的是要知道你想获取哪个iface的MAC地址,因为可能存在许多(蓝牙、多个网络接口卡等)。

如果您知道需要获取MAC地址的iface的IP地址,则可以使用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'

8

您可以使用跨平台的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 then [addr.address for n in nics for addr in nics[n] if n == 'enp4s0' and addr.family == socket.AF_PACKET] results in ['ab:cd:ef:01:02:03'] - Donn Lee

5
跨平台的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)

免责声明:我是该包的作者。

更新(2019年1月14日):该包现在仅支持Python 2.7+和3.4+。如果您需要使用旧版本的Python(2.5、2.6、3.2、3.3),您仍然可以使用旧版本的该包。


以上变量的标准输出:无 无 无 无 00:00:00:00:00:00 无 - Napolean
这些只是用法示例。您需要将参数替换为适用于您的系统的值,这很可能是您获取空结果的原因。例如,“eth0”不适用于Windows系统,“Ethernet 3”不适用于Linux系统,但两者都包含在上面作为示例,以便您知道如何在两个平台上使用库。注意:“localhost”始终返回“00:00:00:00:00:00”。 - Ghost of Goes

2
请注意,您可以使用条件导入在Python中构建自己的跨平台库。例如:
import platform
if platform.system() == 'Linux':
  import LinuxMac
  mac_address = LinuxMac.get_mac_address()
elif platform.system() == 'Windows':
  # etc

这将允许您使用os.system调用或特定于平台的库。

6
这并不是一个真正的答案,只是一条评论。 - Stefano

2

要获取eth0接口的MAC地址,

import psutil

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接