使用 Python 扫描局域网设备并获取设备信息
import os
import subprocess
import socket
from scapy.all import srp, Ether, ARP, conf
import threading
mac_name_mapping = {
"00:e0:4c:29:e2:5b": "我的台式机711",
"08:5c:1b:7c:5b:fe": "cmcc.wifi",
"14:49:d4:af:93:3f": "小米13",
"6e:3e:07:54:b5:b3": "红米note11",
"48:2c:a0:49:86:29": "mi8 se",
"90:78:b2:50:fa:46": "红米k20",
"9c:9c:1f:40:d5:ed":"充电插座",
"3c:61:05:d4:5c:15": "院子灯"
# 继续添加其他设备的 MAC 地址和主机名
}
def ping_device(ip):
"""
Ping 设备,检查是否在线
"""
try:
# print(ip)
output = subprocess.check_output(["ping", "-c", "1", ip], universal_newlines=True)
# print(output)
if "TTL" in output:
return True
return False
except subprocess.CalledProcessError:
return False
def get_mac_address(ip):
"""
使用 ARP 获取 MAC 地址
"""
conf.verb = 0 # 禁用冗长的输出
ans, _ = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ip), timeout=2, retry=2)
for _, rcv in ans:
return rcv[Ether].src
return None
def get_device_name(ip):
"""
通过 IP 地址获取设备名
"""
try:
device_name = socket.gethostbyaddr(ip)[0]
except socket.herror:
device_name = None
return device_name
def scan_ip(ip, results):
"""
扫描单个 IP,获取设备的 IP、MAC 地址和名称
"""
if ping_device(ip):
mac_address = get_mac_address(ip)
device_name = get_device_name(ip)
if not device_name:
if mac_address in mac_name_mapping:
device_name = mac_name_mapping[mac_address]
results.append({"ip": ip, "mac": mac_address, "name": device_name})
def scan_network(network_range):
"""
使用多线程扫描指定网段
"""
threads = []
results = []
for i in range(1, 255):
ip = f"{network_range}.{i}"
thread = threading.Thread(target=scan_ip, args=(ip, results))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
return results
if __name__ == "__main__":
network_range = "192.168.31" # 根据实际情况调整
devices = scan_network(network_range)
for device in devices:
print(f"IP: {device['ip']}, MAC: {device['mac']}, Name: {device['name']}")
大纲
-
引言
- 介绍局域网设备扫描的用途(例如,网络管理、设备监控)。
- 提及 Python 的强大功能和可扩展性。
-
环境准备
- 确保安装 Python 和相关库(如
scapy
)。 - 提及必要的系统权限(如管理员权限)以便执行网络扫描。
- 确保安装 Python 和相关库(如
-
代码分析
- 逐段分析代码,解释其功能和实现逻辑。
代码详细分析
import os
import subprocess
import socket
from scapy.all import srp, Ether, ARP, conf
import threading
- 导入必要的库:
os
和subprocess
用于执行系统命令(如ping
)。socket
用于进行网络编程,获取设备名称。scapy
是一个强大的网络包处理库,用于发送和接收网络数据包。threading
用于实现多线程扫描。
设备 MAC 地址到主机名的映射
mac_name_mapping = {
"00:e0:4c:29:e2:5b": "我的台式机711",
"08:5c:1b:7c:5b:fe": "cmcc.wifi",
"14:49:d4:af:93:3f": "小米13",
"6e:3e:07:54:b5:b3": "红米note11",
"48:2c:a0:49:86:29": "mi8 se",
"90:78:b2:50:fa:46": "红米k20",
"9c:9c:1f:40:d5:ed":"充电插座"
}
- 映射字典:维护一个 MAC 地址和主机名的映射字典。这样可以在 DNS 查询失败时提供更直观的设备名称。
设备在线检查
def ping_device(ip):
"""
Ping 设备,检查是否在线
"""
try:
output = subprocess.check_output(["ping", "-c", "1", ip], universal_newlines=True)
if "TTL" in output:
return True
return False
except subprocess.CalledProcessError:
return False
- 功能:通过
ping
命令检查设备是否在线。如果设备响应,则返回True
,否则返回False
。 - 改进点:可以根据需求调整
ping
的参数,例如增加超时时间。
获取 MAC 地址
def get_mac_address(ip):
"""
使用 ARP 获取 MAC 地址
"""
conf.verb = 0 # 禁用冗长的输出
ans, _ = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ip), timeout=2, retry=2)
for _, rcv in ans:
return rcv[Ether].src
return None
- 功能:使用 ARP 请求获取给定 IP 地址的 MAC 地址。该函数通过广播 ARP 请求到网络中,然后解析响应以提取 MAC 地址。
获取设备名称
def get_device_name(ip):
"""
通过 IP 地址获取设备名
"""
try:
device_name = socket.gethostbyaddr(ip)[0]
except socket.herror:
device_name = None
return device_name
- 功能:通过反向 DNS 查找获取设备名称。如果查找失败,则返回
None
。
扫描单个 IP 地址
def scan_ip(ip, results):
"""
扫描单个 IP,获取设备的 IP、MAC 地址和名称
"""
if ping_device(ip):
mac_address = get_mac_address(ip)
device_name = get_device_name(ip)
if not device_name:
if mac_address in mac_name_mapping:
device_name = mac_name_mapping[mac_address]
results.append({"ip": ip, "mac": mac_address, "name": device_name})
- 功能:对于每个 IP 地址,首先检查其是否在线。如果在线,则获取其 MAC 地址和设备名称。如果设备名称为
None
,则从映射字典中查找。
多线程扫描网络
def scan_network(network_range):
"""
使用多线程扫描指定网段
"""
threads = []
results = []
for i in range(1, 255):
ip = f"{network_range}.{i}"
thread = threading.Thread(target=scan_ip, args=(ip, results))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
return results
- 功能:使用多线程扫描整个子网,从
192.168.31.1
到192.168.31.254
。这显著提高了扫描速度。
主程序
if __name__ == "__main__":
network_range = "192.168.31" # 根据实际情况调整
devices = scan_network(network_range)
for device in devices:
print(f"IP: {device['ip']}, MAC: {device['mac']}, Name: {device['name']}")
- 功能:定义要扫描的网络范围,调用扫描函数并输出结果。
结论
- 该 Python 脚本可以有效地扫描局域网内的设备,获取其 IP、MAC 地址及设备名称。
- 通过维护 MAC 地址与设备名称的映射,可以更方便地识别设备。
文章结尾
- 讨论脚本的可扩展性和潜在的改进(如添加更多的设备识别功能、使用更高级的库等)。
- 鼓励读者尝试自己修改和扩展代码,适应不同的网络环境。
通过这种结构和内容,你可以撰写一篇详尽的文章,帮助他人理解和使用这个 Python 网络扫描脚本。
本文作者: 永生
本文链接: https://yys.zone/detail/?id=362
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
发表评论
评论列表 (0 条评论)
暂无评论,快来抢沙发吧!