【问题标题】:Obtain MAC Address from Devices using Python使用 Python 从设备获取 MAC 地址
【发布时间】:2025-12-21 03:20:16
【问题描述】:

我正在寻找一种方法(使用 python)从本地网络上的设备获取layer II 地址。 Layer III 地址是已知的。

我们的目标是构建一个脚本,该脚本将定期轮询 IP 地址数据库,确保 MAC 地址没有更改,如果有更改,则通过电子邮件向我自己发送警报。

【问题讨论】:

标签: python ip-address mac-address


【解决方案1】:

听起来您想监控 ARP 欺骗器?在这种情况下,您只需要arpwatch,您附近的每个供应良好的 Linux 发行版都可以使用它。在此处下载资源:http://ee.lbl.gov/

【讨论】:

    【解决方案2】:

    不久前在这个网站上有一个similar question 回答。正如该问题的提问者选择的答案中所提到的,Python 没有内置的方法来做到这一点。您必须调用诸如arp 之类的系统命令来获取ARP 信息,或者使用Scapy 生成您自己的数据包。

    编辑:使用 Scapy from their website 的示例:

    这是另一个工具 持续监控所有接口 机器并打印所有 ARP 请求 看到,即使在 802.11 帧上 Wi-Fi 卡处于监控模式。注意 store=0 参数到 sniff() 以避免 将所有数据包存储在内存中 什么都没有。

    #! /usr/bin/env python
    from scapy import *
    
    def arp_monitor_callback(pkt):
        if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at
            return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%")
    
    sniff(prn=arp_monitor_callback, filter="arp", store=0)
    

    您也可以执行类似于已验证答案的操作。见https://scapy.readthedocs.io/en/latest/routing.html

    >>> mac = getmacbyip("10.0.0.1")
    >>> mac
    'f3:ae:5e:76:31:9b'
    

    这是完全跨平台的。

    不完全是您正在寻找的东西,但绝对是在正确的轨道上。享受吧!

    【讨论】:

      【解决方案3】:

      使用 Python 回答问题取决于您的平台。我手边没有 Windows,因此以下解决方案适用于我编写它的 Linux 机器。对正则表达式稍加改动即可使其在 OS X 中运行。

      首先,您必须 ping 目标。这将把目标——只要它在你的网络掩码内,在这种情况下听起来就好像——在你系统的 ARP 缓存中。观察:

      13:40 jsmith@undertow% ping 97.107.138.15
      PING 97.107.138.15 (97.107.138.15) 56(84) bytes of data.
      64 bytes from 97.107.138.15: icmp_seq=1 ttl=64 time=1.25 ms
      ^C
      
      13:40 jsmith@undertow% arp -n 97.107.138.15
      Address                  HWtype  HWaddress           Flags Mask            Iface
      97.107.138.15            ether   fe:fd:61:6b:8a:0f   C                     eth0
      

      知道了这一点,您就可以使用一些子进程魔法——否则您正在自己编写 ARP 缓存检查代码,而您不想这样做:

      >>> from subprocess import Popen, PIPE
      >>> import re
      >>> IP = "1.2.3.4"
      
      >>> # do_ping(IP)
      >>> # The time between ping and arp check must be small, as ARP may not cache long
      
      >>> pid = Popen(["arp", "-n", IP], stdout=PIPE)
      >>> s = pid.communicate()[0]
      >>> mac = re.search(r"(([a-f\d]{1,2}\:){5}[a-f\d]{1,2})", s).groups()[0]
      >>> mac
      "fe:fd:61:6b:8a:0f"
      

      【讨论】:

      • 哈,这正是我正在写的答案!
      • 如果您没有 arp(OpenWRT 没有)并且有 ip-neighbour 包(可以安装在 OpenWRT 上),那么您可以使用此命令获取 pid 的值:pid = Popen(["ip", "neigh", "show", IP], stdout=PIPE)
      【解决方案4】:

      对于基于 Unix 的系统:

      #!/usr/bin/env python2.7
      
      import re
      import subprocess
      arp_out =subprocess.check_output(['arp','-lan'])
      
      re.findall(r"((\w{2,2}\:{0,1}){6})",arp_out)
      

      将返回带有 mac 的元组列表。 scapy 是一个了不起的工具,但在这种情况下似乎有点矫枉过正

      【讨论】:

        【解决方案5】:

        在 Linux 中,有时您会错过命令行工具“arp”。例如,一个基本的 yocto linux 嵌入式环境映像。

        没有“arp”工具的另一种方法是读取和解析文件/proc/net/arp:

        root@raspberrypi:~# cat /proc/net/arp
        IP address       HW type     Flags       HW address            Mask     Device
        192.168.1.1      0x1         0x2         xx:xx:xx:xx:xx:xx     *        wlan0
        192.168.1.33     0x1         0x2         yy:yy:yy:yy:yy:yy     *        wlan0
        

        【讨论】:

          【解决方案6】:

          一个更简单的方法,如果在 linux 上:

          print os.system('arp -n ' + str(remoteIP))

          你会得到:

              Address        HWtype  HWaddress           Flags Mask            Iface
              192.168.....   ether   9B:39:15:f2:45:51   C                     wlan0
          

          【讨论】:

            【解决方案7】:

            使用scapy的简单解决方案,扫描192.168.0.0/24子网如下:

            from scapy.all import *
            
            ans,unans = arping("192.168.0.0/24", verbose=0)
            for s,r in ans:
                print("{} {}".format(r[Ether].src,s[ARP].pdst))
            

            【讨论】:

              【解决方案8】:

              Python 3.7 的一般更新。备注:arp 的选项 -n 不提供 windows 系统上的 arp 列表,如为基于 linux 的系统提供的某些答案。使用选项-a,如此处答案中所述。

              from subprocess import Popen, PIPE
              
              pid = Popen(['arp', '-a', ip], stdout=PIPE, stderr=PIPE)
              
              IP, MAC, var = ((pid.communicate()[0].decode('utf-8').split('Type\r\n'))[1]).split('     ')
              IP  =  IP.strip(' ')
              MAC =  MAC.strip(' ')
              
              if ip == IP:
                  print ('Remote Host : %s\n        MAC : %s' % (IP, MAC))
              

              【讨论】: