运行截图如下:

python 获取别的设备共享文件 python获取局域网中的ip和mac地址_python

代码

直接贴代码了,里面有很详细的注释:

# -*- coding: utf-8 -*-
import os
import re
import socket


# 获取指定IP地址的MAC地址
def getMac(target_IP):
    # 初始化 用正则表达式're'编译出匹配MAC地址的正则表达式对象
    patt_mac = re.compile('([a-f0-9]{2}[-:]){5}[a-f0-9]{2}', re.I)
    # ping
    os.popen('ping -n 1 -w 500 {} > nul'.format(target_IP))
    # 然后使用'arp'命令获取该IP地址对应的MAC地址 返回一个类文件对象 可以通过 read 方法获取命令的输出结果
    arp_file = os.popen('arp -a {}'.format(target_IP))
    # 使用正则表达式'self.patt_mac'在输出结果中查找符合 MAC 地址格式的字符串 并返回找到的第一个匹配项 即 IP 对应的 MAC 地址
    mac_addr = patt_mac.search(arp_file.read())

    # 根据正则表达式对象匹配MAC地址 如果匹配到了就返回MAC地址 否则返回None
    if mac_addr:
        mac_addr = mac_addr.group()
        return mac_addr
    else:
        return '00-00-00-00-00-00'


# 获取与本机在同一局域网下的设备 IP与MAC的映射
if __name__ == '__main__':
    '''
    # 返回默认网卡对应的IP地址
    ip_addr = socket.gethostbyname(socket.gethostname())
    '''
    # 创建一个UDP套接字
    socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 连接到一个公共ip地址
    socket.connect(('www.baidu.com', 80))
    # 获取本地套接字的地址信息 这个地址信息就是本机在局域网中的IP地址
    ip_addr = socket.getsockname()[0]
    # 关闭套接字
    socket.close()

    print("当前本机局域网ip地址为:" + ip_addr + '\n')
    # 获取网关
    idx = 0
    cnt = 0
    for i in ip_addr:
        idx = idx + 1
        if (i == '.'):
            cnt = cnt + 1
            if (cnt == 3):
                break
    gate_way = ip_addr[0:idx]
    # 循环发送arp请求及获取对应ip的mac地址
    for i in range(0, 255):
        target_IP = gate_way + str(i)
        if (target_IP != ip_addr):
            target_Mac = getMac(target_IP)
            if (target_Mac == "00-00-00-00-00-00"):
                print("{:>15}".format(target_IP) + ":\t\tTimeout!")
            else:
                print("{:>15}".format(target_IP) + ":\t\t" + target_Mac)

胡说八道

0x01

细心的你可能发现了,我注释掉了这么一句代码:

# 返回默认网卡对应的IP地址
ip_addr = socket.gethostbyname(socket.gethostname())

这是我刚开始用来获取本机 ip 的方法,先通过 socket.gethostname() 获取本机的主机名,然后通过 socket.gethostbyname() 将主机名转换为 ip 地址。

经过在多个不同的局域网下测试发现,如果你有装有虚拟机或者有多个网卡的话,可能会返回与你期望的 IP 地址不一致的结果,我这有时候就会返回虚拟机的虚拟网卡的 ip…

所以换成了创建套接字去访问公共地址的方法。


修正:

后面发现使用套接字的方法也有 bug,如果 ip网关 的网络号不同时,跑出来的全是 Timeout(还没理解 遇到了就记录一下

python 获取别的设备共享文件 python获取局域网中的ip和mac地址_python_02

方法总比困难多,我们可以通过执行 ‘route print’ 命令获取 默认路由 0.0.0.0 的网关:

route print

python 获取别的设备共享文件 python获取局域网中的ip和mac地址_IP_03

然后 像上面提取MAC地址那样提取出来用就好。

0x02

另外,这样似乎并不能保证当前能查到 MAC 地址的设备一定接入了局域网,因为可能这只是你的 arp缓存,而不是刚刚更新的。目前只想到这么两种解决方法:

1.在运行程序前,清下 arp 缓存。以管理员身份运行 powershell,执行:

arp -d *

2.使用 Python 的 Scapy 库(它可以用于构造和解析网络数据包)发送 ICMP Echo Request 报文,并解析 ICMP Echo Reply 报文中的源 MAC 地址。