获取 MAC 地址

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

有人知道一种跨平台的方法(windows 和 linux)来获取 MAC 地址吗?如果没有,还有人知道比我上面列出的方法更优雅的方法吗?

187195 次浏览

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

我不知道统一的方法,但这里有一些你可能会发现有用的东西:

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 地址。

对于 Linux,可以使用 SIOCGIFHWADDR ioctl 检索 MAC 地址。

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 模块是否可以获得这些信息。您可以使用 类型直接调用 ioctl。

注意,您可以使用条件导入在 python 中构建自己的跨平台库。

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

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

还有一点需要注意的是,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.

Linux 下针对这个问题的纯 python 解决方案获取特定本地接口的 MAC,最初作为 vishnubob 的注释发布,并在 这个激活的配方中的 Ben Mackey 上得到了改进

#!/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,让我介绍一个 shell 脚本,它将显示 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(在重新启动时将暂时恢复为实际地址)。

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

知道你想要 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'

有时我们有不止一个网络接口。

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

你可以用 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]

如果您不介意采用依赖关系,那么跨平台的 Getmac包将为此工作。它适用于 Python 2.7 + 和3.4 + 。它将尝试许多不同的方法,直到获得一个地址或返回 Nothing。

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) ,仍然可以使用旧版本的包。

或者,

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

为了得到 eth0接口的 MAC 地址,

import psutil


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


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

Nice 实际上在 dictionary 中返回一个 dictionary 它返回一个列表,在列表中返回一个订书钉。但是 Nics [‘ Ethernet’][0]地址迭代解决了这个问题。

import psutil


nics = psutil.net_if_addrs()


mac_address = nics['Ethernet'][0].address


print(mac_address)