恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Python自动化巡检网络设备:SNMP与SSH脚本实战
首页
资讯中心
/
Python自动化巡检网络设备:SNMP与SSH脚本实战
Python自动化巡检网络设备:SNMP与SSH脚本实战
发布时间:2026/10/20 3:55:54
简介Python网络设备自动巡检脚本面向网络运维工程师与Python自动化学习者解决大规模网络环境中设备状态、配置及接口检查依赖人工、效率低的问题。压缩包为zip格式共7个文件主要包含1个核心Python脚本、5个ini配置文件和1个md说明文档整体仅6KB轻量易用。ini文件分别用于管理邮件列表、设备地址、不同厂商命令及密码等参数便于按需调整README提供使用指引。已有6140人学习下载。通过该资源可快速掌握telnetlib连接网络设备、身份认证、执行show命令、解析输出及关闭连接的全流程并熟悉将巡检结果写入文件或通过邮件发送的扩展方法。适合希望用Python实现网络设备批量巡检、降低人工失误率的初级至中级运维人员。1. 自动巡检脚本把每天一小时的手工登录压缩成几分钟的定时任务某公司网络管理员每天早上的第一件事是挨台登录交换机、路由器敲show cpu、show memory、show interface这类命令确认设备没告警、没跑满、没宕机。二十多台设备下来一个小时就没了而且人工操作最大的问题不是慢是漏——漏看一行错误计数漏刷一条接口 down 的状态等用户报障才回头查日志黄花菜都凉了。这个「Python 通过脚本自动巡检网络设备」的项目做的就是把这件重复劳动彻底脚本化先探测设备活没活再通过 SNMP 和 SSH 把设备的 CPU、内存、接口流量、关键状态全抓回来和预设阈值比对最后自动生成表格报告并把异常通过邮件发出去。适合两类人一类是背着几十台上百台设备、想从重复登录里解脱出来的网络运维另一类是正在学网络编程、想看看 socket 并发、SNMP、SSH 自动化这些技术怎么落地的 Python 开发者。2. 整体架构与技术选型从设备清单到巡检报告数据是怎么流动的2.1 巡检对象怎么描述YAML 设备清单与阈值配置这个项目里我始终坚持一个原则代码里不出现任何一台真实设备的 IP、账号或者阈值所有环境相关的信息全部外置到配置文件。这样做的好处非常直接——换一批设备或者加一台新交换机只需要改 YAML 文件不需要动一行 Python 代码非开发背景的运维同事也能自己维护。设备清单devices.yaml的核心结构大概长这样devices: - hostname: core-sw-01 ip: 192.168.10.1 vendor: cisco device_type: cisco_ios role: core location: 机房A-01机柜 snmp: version: 2c community: public_ro port: 161 ssh: username: opsuser password: {{ env_SSH_PASSWORD }} port: 22 check_items: - cpu - memory - interface - uptime阈值文件thresholds.yaml单独拆出来因为巡检策略和网络环境强相关。同一个 CPU 使用率在核心交换机上可能 70% 就该告警在接入交换机上 90% 也许还能扛一阵子thresholds: cpu_usage: 80 memory_usage: 85 interface_errors: 10 interface_drops: 5 ping_loss_rate: 20 ping_rtt_ms: 200参数说明snmp.community用的是只读 community 字符串这是生产环境的底线绝不能用读写权限的 community 做自动化采集ssh.password这里不建议直接明文写在 YAML 里项目里用了一个{{ env_SSH_PASSWORD }}的占位符由启动脚本从环境变量注入避免敏感信息直接落盘。check_items是这台设备要检查的指标列表不同角色设备采集的内容可以不一样核心设备多查几项接入设备少查几项。2.2 四种采集手段选型TCP 探测、SNMP、SSH 与数据汇总选型这件事踩过的坑比看文档学到的东西多得多。先说连通性探测很多人第一反应是 ICMP ping但在真实网络里很多安全策略会直接丢弃 ICMP 报文设备活着却 ping 不通的情况太常见了。项目里换成了 TCP 端口探测——设备的管理端口SSH 的 22 或 Telnet 的 23是必须对外可达的TCP 握手成功比 ICMP 回包更能代表「设备可管理」这个真实状态。SNMP 负责取性能指标。CPU、内存、接口流量这些东西用 SNMP v2c 的 GET 请求就能拿到OID 是标准的不需要登录设备敲命令对设备自身的开销也小适合批量采集。缺点是对设备的具体型号有依赖不同厂商的 OID 并不完全一致这个在后面避坑章节会重点说。SSH 负责取 SNMP 拿不到的东西。比如接口的错误计数详情、路由表、生成树状态、日志缓冲区这些只能通过登录设备执行show命令获取。项目里用了netmiko这个库来封装 SSH 交互它对主流厂商的设备类型做了适配Cisco、华为、H3C、锐捷基本都覆盖了比自己裸写 paramiko 处理各种--More--分页和提示符要省心得多。最后数据汇总用的是 pandas DataFrame。所有采集结果不管来源是 SNMP 还是 SSH统一转成结构化数据合并到一个总表里做阈值比对和报告生成。这样设计的好处是后续想接 influxdb、Prometheus 这类时序库只需要改汇总和导出的环节采集部分完全不用动。2.3 工程目录结构与运行入口整个项目是一个标准的单包结构所有模块按职责拆开方便按需扩展automation_network_inspection/ ├── config/ │ ├── devices.yaml │ └── thresholds.yaml ├── core/ │ ├── __init__.py │ ├── check_connectivity.py │ ├── snmp_collector.py │ ├── ssh_collector.py │ ├── alarm_sender.py │ ├── report_generator.py │ └── inspection_orchestrator.py ├── utils/ │ ├── __init__.py │ └── logger.py ├── reports/ │ └── (生成的巡检报告存放目录) ├── logs/ │ └── (运行日志存放目录) ├── requirements.txt ├── run_inspection.py └── README.mdrun_inspection.py是整个巡检的入口它负责加载配置、组装核心模块、触发巡检流程并接收命令行参数。core包里的模块各干一件事check_connectivity做预检、snmp_collector和ssh_collector负责采集、alarm_sender发告警、report_generator生成报告inspection_orchestrator是编排者把整个流程串起来。这种按职责拆分的结构比把所有逻辑塞进一个几百行的脚本里好维护得多——想单独测某台设备的连通性直接跑check_connectivity.py就行不用把整个巡检流程都走一遍。3. 核心模块拆解一次巡检任务从进入到返回的完整链路3.1 连通性预检多线程探测与超时控制巡检的第一步不是直接去采集而是先确认设备活着。这个模块如果设计不好会拖垮整个巡检流程——假设有 50 台设备其中 3 台已经宕机如果每台都等到 TCP 连接超时默认可能 30 秒光预检就要多耗时一分半。所以这里必须做两件事并发探测 超时控制。# core/check_connectivity.py import socket from concurrent.futures import ThreadPoolExecutor, as_completed DEFAULT_TIMEOUT 5 def check_tcp_port(ip: str, port: int, timeout: int DEFAULT_TIMEOUT) - bool: 对设备管理端口做 TCP 握手探测代替 ICMP ping。 sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) try: result sock.connect_ex((ip, port)) return result 0 except socket.error: return False finally: sock.close() def batch_check(devices: list, max_workers: int 8) - dict: 并发探测所有设备返回 {ip: True/False} 的存活状态映射。 status {} def _check_one(device): ip device[ip] # 优先探测 SSH 端口如果设备没开 SSH 再试 Telnet 端口 port device.get(ssh, {}).get(port, 22) return ip, check_tcp_port(ip, port) with ThreadPoolExecutor(max_workersmax_workers) as executor: futures [executor.submit(_check_one, dev) for dev in devices] for future in as_completed(futures): ip, ok future.result() status[ip] ok return status逻辑说明check_tcp_port创建 socket 并设置超时时间connect_ex的好处是连接失败不会抛异常而是返回一个非零的错误码这样代码逻辑很简洁——非零就是不通。batch_check用ThreadPoolExecutor控制并发数as_completed保证哪个先返回就先处理哪个不会因为某台设备卡住而阻塞整体进度。参数说明timeout5是给 TCP 握手让出的时间窗口在跨地域管理场景下建议放宽到 810 秒max_workers8是并发上限不是开得越大越好如果设备本身性能较弱过大的并发探测同样会把设备的管理面打满这个在避坑章节会展开。这里还做了一个小的容错设计优先探测 22 端口因为现代设备基本都开 SSHTelnet 已经被禁用或作为兜底存在。3.2 SNMP 性能采集一个 GET 请求拿到 CPU、内存与接口流量连通性预检通过后进入实际采集阶段。SNMP 采集模块是这个项目的核心之一它处理的对象是那些不需要登录设备就能拿到的性能指标。# core/snmp_collector.py from pysnmp.hlapi import ( getCmd, CommunityData, SnmpEngine, UdpTransportTarget, ContextData, ObjectType, ObjectIdentity ) OIDS { cpu_usage: 1.3.6.1.4.1.9.9.109.1.1.1.1.3.1, # 思科 CPU 使用率五秒平均 memory_usage: 1.3.6.1.4.1.9.9.48.1.1.1.5.1, # 思科内存池利用率 interface_in_octets: 1.3.6.1.2.1.2.2.1.10.1, # 接口入方向字节数 interface_out_octets: 1.3.6.1.2.1.2.2.1.16.1, # 接口出方向字节数 system_uptime: 1.3.6.1.2.1.1.3.0, } def collect_snmp_metrics(ip: str, community: str, port: int 161) - dict: 对单台设备发起 SNMP v2c GET 请求返回指标字典。 result {} for metric_name, oid in OIDS.items(): try: error_indication, error_status, error_index, var_binds next( getCmd( SnmpEngine(), CommunityData(community, mpModel1), # mpModel1 表示 SNMP v2c UdpTransportTarget((ip, port), timeout3, retries1), ContextData(), ObjectType(ObjectIdentity(oid)), ) ) if error_indication: result[metric_name] None continue if error_status: result[metric_name] None continue result[metric_name] var_binds[0][1].prettyPrint() except Exception: result[metric_name] None return result逻辑说明这里用的是同步getCmd调用逐条 OID 去 GET。为什么不一次性bulkGet因为在真实网络环境里部分老设备对批量 GET 的响应不稳定可能出现某个 OID 无响应导致整批采集失败的情况。逐条 GET 虽然慢一点但容错性最好——某条失败不会拖累其他指标。prettyPrint()把 SNMP 返回值从内部类型转成字符串CPU 使用率拿到的可能是5这样的字符串还需要在后续转成 int 或 float 做阈值比对。这里返回None而不是抛异常是因为持久化数据时None可以落空值而异常会导致整台设备采集中断。参数说明timeout3, retries1表示单条 OID 最多等 3 秒、失败重试 1 次。对一个有 6 个采集项的设备理论上最坏情况是 6×(33)36 秒但正常网络下每个 GET 都在毫秒级完成。如果设备数量大建议把单台超时调到 2 秒内并在多个采集线程之间做并发而不是串行等。实际使用中还要面对另一个问题——非思科设备的 OID 完全不同。OIDS 字典里前两个是思科的私有 MIB1.3.6.1.4.1.9是思科企业号华为、H3C 的 CPU 和内存 OID 是另一套。项目里对这个问题做了一个简单的解决在devices.yaml里给每台设备标注厂商采集时根据厂商选择对应的 OID 映射表。这个映射表放在snmp_collector.py的独立字典里新增厂商设备时只需要加一张表不用改采集逻辑。3.3 SSH 命令行巡检用 netmiko 批量执行 show 命令SNMP 能拿到指标数据但拿不到接口错误计数、端口协商状态、生成树角色变更这类运维细节。这些信息藏在设备的 CLI 输出里必须通过 SSH 登录去执行命令行。项目用 netmiko 来做这块封装。# core/ssh_collector.py from netmiko import ConnectHandler def collect_show_commands(device: dict, commands: list) - dict: SSH 登录设备逐个执行 show 命令并返回输出。 ssh_config device[ssh] device_type device[device_type] connection ConnectHandler( ipdevice[ip], usernamessh_config[username], passwordssh_config[password], device_typedevice_type, portssh_config[port], timeout10, banner_timeout15, auth_timeout15, session_timeout30, ) connection.send_command(terminal length 0) outputs {} for cmd in commands: # expect_string 提示 netmiko 等待哪个提示符避免过早返回不全的输出 output connection.send_command(cmd, read_timeout20) outputs[cmd] output.strip() connection.disconnect() return outputs逻辑说明连接参数里timeout是 TCP 连接超时auth_timeout是登录认证的等待时间banner_timeout是处理设备 banner 提示的专用超时。这几项分开设置的原因是设备登录阶段最容易卡住——banner 过长、认证缓慢、VTY 线路拥塞都会导致登录卡死分开设置可以让报错精确定位到具体环节。代码里先发送terminal length 0取消分页这是 SSH 自动化的关键一步。如果不关闭分页一条show running-config输出超过一屏时设备会停在--More--提示符netmiko 会找不到最终的提示符而超时拿到的输出还不完整。send_command里的read_timeout20是针对慢命令的兜底——比如show ip route在路由表很大的设备上可能执行很久默认的 read_timeout 往往不够用。这块的坑主要在device_type必须写对。cisco_ios和huawei的终端交互逻辑差异很大提示符、分页关闭命令都不一样。netmiko 支持的设备类型在官方文档里有完整列表新接入一台厂商设备时先查这个列表比自己手写正则去匹配提示符靠谱得多。3.4 告警判定与报告生成阈值比对、Excel 输出和邮件通知采集只是手段巡检的最终价值体现在「数据拿回来了然后呢」——没问题的变成报告归档有问题的变成告警直接推给运维。这个模块把两者串在一起。# core/report_generator.py import pandas as pd from datetime import datetime def evaluate_and_generate(all_data: list, thresholds: dict, alive_map: dict) - pd.DataFrame: 将采集数据与阈值比对生成包含状态标记的 DataFrame。 rows [] for item in all_data: device_ip item[ip] if not alive_map.get(device_ip, False): rows.append({ ip: device_ip, device_name: item[hostname], cpu: None, memory: None, status: DOWN, alert_message: 设备不可达 }) continue cpu item.get(cpu) memory item.get(memory) alerts [] if cpu is not None and int(cpu) thresholds[cpu_usage]: alerts.append(fCPU 使用率 {cpu}% 超过阈值 {thresholds[cpu_usage]}%) if memory is not None and int(memory) thresholds[memory_usage]: alerts.append(f内存使用率 {memory}% 超过阈值 {thresholds[memory_usage]}%) rows.append({ ip: device_ip, device_name: item[hostname], cpu: cpu, memory: memory, status: ALERT if alerts else NORMAL, alert_message: ; .join(alerts) if alerts else }) df pd.DataFrame(rows) # 保存一份带日期的 Excel 文件到 reports 目录 filename freports/inspection_{datetime.now().strftime(%Y%m%d)}.xlsx with pd.ExcelWriter(filename, engineopenpyxl) as writer: df.to_excel(writer, sheet_name巡检总览, indexFalse) return df逻辑说明先检查设备存活状态对宕机设备直接标记 DOWN 并生成不可达告警不再继续处理它的采集数据——这是个很关键的短路逻辑避免在宕机设备上浪费时间解析空数据。然后逐台比对 CPU 和内存把超阈值的记录标记为 ALERT 并拼接告警内容。status列是一个便于阅读的三态值NORMAL、ALERT、DOWN后续邮件和报表排序都以这列为依据。参数说明thresholds[cpu_usage]和thresholds[memory_usage]来自前面说的thresholds.yaml百分比阈值建议保留一位小数方便调整策略。pd.ExcelWriter用 openpyxl 引擎支持写入多个 sheet当前版本先写入总览扩展时可以按设备类型分组写入多个 sheet。告警邮件的发送逻辑在alarm_sender.py中核心是基于smtplib实现# core/alarm_sender.py import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart def send_alert_email(subject: str, html_content: str, smtp_config: dict): 发送 HTML 格式的告警邮件。 msg MIMEMultipart() msg[From] smtp_config[from_addr] msg[To] , .join(smtp_config[to_addrs]) msg[Subject] subject body MIMEText(html_content, html, utf-8) msg.attach(body) server smtplib.SMTP(smtp_config[server], smtp_config[port]) server.starttls() server.login(smtp_config[username], smtp_config[password]) server.send_message(msg) server.quit()逻辑说明starttls()把明文连接升级为加密连接这是连接外部邮件服务器的基本要求。html_content由report_generator把 DataFrame 转成 HTML 表格后传入让收到的邮件直接展示一个带颜色的告警表格而不是贴一段 CSV 文本。MIMEMultipart是为了后续扩展时能同时附带附件比如完整的 Excel 巡检报告当前版本只发送 HTML 正文。4. 把脚本跑起来环境准备、依赖安装与首次巡检4.1 环境准备与依赖安装这个项目依赖 Python 3.8 及以上版本。因为用到了concurrent.futures3.2、f-string3.6和dataclass3.73.8 起步是最稳妥的选择也方便在各类 Linux 发行版和 Windows 上直接跑。依赖清单在requirements.txt里netmiko4.2.0 pysnmp4.4.12 pandas2.0.0 openpyxl3.1.0 PyYAML6.0安装命令pip install -r requirements.txt逻辑说明netmiko是基于 paramiko 的更高层封装它把各厂商设备的交互差异提示符、分页关闭、enable 模式切换都做了适配这也是我们在 3.3 节里能直接设置device_typecisco_ios就完成连接的原因。pysnmp是 Python 生态里最常用的 SNMP 库纯 Python 实现不需要编译原生扩展安装省心。4.2 填写设备清单并启动首次巡检首次运行前需要把devices.yaml里的设备信息替换成自己网络环境的真实数据。建议先用一台测试设备跑通流程再逐步加入更多设备。启动命令很简单python run_inspection.py --config config/devices.yaml巡检过程会在控制台输出关键日志节点2025-01-10 09:00:01 [INFO] 加载设备清单共 3 台设备 2025-01-10 09:00:01 [INFO] 开始连通性预检... 2025-01-10 09:00:03 [INFO] 连通性预检完成3 台可达0 台不可达 2025-01-10 09:00:03 [INFO] 开始 SNMP 性能采集... 2025-01-10 09:00:07 [INFO] SNMP 采集完成 2025-01-10 09:00:07 [INFO] 开始 SSH 命令巡检... 2025-01-10 09:00:15 [INFO] SSH 巡检完成 2025-01-10 09:00:15 [INFO] 生成巡检报告reports/inspection_20250110.xlsx 2025-01-10 09:00:16 [INFO] 发现 1 条告警已发送邮件通知这个输出顺序和 3.x 章节讲的执行链路严格对应日志本身就能作为执行流程的自检工具——如果哪一步没出现就说明对应模块出了问题。--config参数指定配置文件路径不传时默认读取config/devices.yaml。4.3 定时任务与日志排查巡检的价值在于持续性和可预测性手工跑一次只是验证脚本可用实际使用必须挂到定时任务里。Linux 环境用 cronWindows 环境用任务计划程序# 每天上午 9 点执行巡检 0 9 * * * cd /opt/automation_network_inspection /usr/bin/python3 run_inspection.py logs/cron.log 21日志是排查问题的第一入口。utils/logger.py里配置了按日期滚动的文件日志每天的运行记录单独存放方便回溯历史问题。当巡检报告没有按时出现时建议优先看三个地方cron 的执行记录有没有调起脚本、logs目录下当天的日志文件有没有生成、日志里最后一条完整输出的模块是哪个。项目里日志级别统一用 INFO只在采集失败时打 WARNING不会用 DEBUG 刷屏看起来也清爽很多。5. 常见问题与避坑指南自动巡检的几个经典翻车现场5.1 并发数过高核心交换机 CPU 被打满现象巡检运行期间核心交换机的 CPU 使用率反常飙升从正常的 20% 冲到 80% 以上网络转发出现延迟甚至影响业务流量。原因连通性预检和 SNMP 采集两个模块都开了并发默认max_workers8加上进程本身还会起线程瞬时并发请求太多。网络设备的管理面CPU 处理 SNMP/SSH 报文的能力远弱于服务器8 个并发对服务器不算什么对一台老交换机可能直接打爆管理面。解决把并发数降下来。项目里在run_inspection.py里暴露了--workers参数降低到 3 或 4 就不会再出现这个问题。另外一个附加措施是把巡检时间窗口和业务高峰错开在 cron 里改成凌晨或午休时段执行。5.2 SNMP 返回空值报表里全是一串空现象巡检正常跑完但生成的 Excel 报告里 CPU 和内存列全部为空邮件告警却一条都没报。原因设备没有启用 SNMP或者devices.yaml里填写的 community 字符串与实际设备不匹配。更隐蔽的一种情况是 OID 不对——默认配置里的思科 OID 用在华为设备上返回的一定是空。这类问题的排查成本很高因为 SNMP 的报错信息往往只是一个No Such Instance。解决在把设备加入自动巡检前先用snmpwalk或snmpget命令行工具手动验证一遍确认设备开启 SNMP、community 正确、目标 OID 能返回数值。项目里我通常在snmp_collector.py里加一个--probe模式单独对一台设备执行 OID 探测并打印原始返回值确认无误后再加入正式巡检。5.3 SSH 输出被分页截断命令结果只有一半现象SSH 采集到的show run输出在报告里只剩前几屏后面的配置内容全部丢失。有时还会报Search pattern not detected的超时错误。原因设备开启分页输出命令结果超过一屏后停在--More--。terminal length 0没有成功执行或者执行了但设备型号不识别这条命令某些设备用screen-length 0 temporary或terminal paging disable。解决netmiko 连接成功后先发送分页关闭命令发送后最好主动验证一下——再发一条show version | include uptime看输出是否完整。不同厂商的分页关闭命令不一样netmiko 的device_type映射表里已经内置了对应命令确保device_type填正确是根治方案。此外send_command加read_timeout参数给慢命令留足执行时间。5.4 设备短时间重启告警邮件刷屏现象某台交换机因为固件升级自动重启在 10 分钟内反复上下线。自动巡检正好落在这个时间窗口内连续跑了三轮发出去十几封 DOWN 告警邮件运维的手机被刷屏。原因巡检逻辑是「发现异常即告警」没有考虑状态的持续性和重复性。设备因为升级、断电等原因临时不可达巡检把它判定为 DOWN 并触发告警下一轮恢复后又触发 RECOVER 告警来回抖动。解决在告警判定模块里加一个状态漂移抑制逻辑。连续两轮比如间隔 10 分钟都判定为 DOWN 才真正触发告警恢复时同样要连续两轮确认正常才发恢复通知。项目里我在alarm_sender.py里加了一个alert_cache字典缓存每台设备上一轮的状态只有状态发生变更且连续两次确认后才发送邮件。这套逻辑上线后告警邮件数量至少减掉了七成。5.5 Excel 报表中文乱码现象生成的巡检报告打开后中文全部变成乱码设备名和告警内容没法看。原因Excel 文件本身存储的是 Unicode 编码这个乱码往往不是写入环节的问题而是文件被 CSV 模式打开了或者数据在写入前已经是乱码。解决pandas 写 Excel 用 openpyxl 引擎时DataFrame 里的字符串必须是正常的str类型。如果采集数据来自某些厂商设备的字节流需要在采集模块里统一做decode(utf-8, errorsignore)避免非法字节进入 DataFrame。另外如果同时输出 CSV 文件用于归档写入时要用utf-8-sig编码而不是默认的utf-8不然用 Excel 直接打开 CSV 时中文必乱。项目里默认只出 Excel 报告就是为了一劳永逸避开中文编码的坑。6. 二次开发把脚本改造成适配自己网络的巡检系统项目跑顺之后二次开发的空间很大这里说几个我实际做过的改造方向按性价比从高到低排序。最直接的扩展是增加新的采集指标。SNMP 模块的 OID 映射表可以无限扩充只要确认设备支持对应 MIB。SSH 模块更简单在devices.yaml的check_items里加一项然后在ssh_collector.py里把这个 item 对应的命令写进配置映射不用改执行逻辑。比如想加一个「检查所有接口是否有 errdisable 状态」的巡检项只需要在commands映射里加入show interface status | include errdisable并给它一个可读的指标名。更进阶的改造是把设备清单接入 CMDB。现在devices.yaml是静态文件新加设备要手动编辑 YAML。如果公司已经有 CMDB 或资产管理系统可以写一个小脚本定时从 CMDB 拉取设备列表动态生成devices.yaml。这样新增设备只要在 CMDB 里登记巡检系统第二天就自动覆盖到它不用手工改配置。同样巡检结果也可以写回 CMDB作为设备健康度的参考数据。再往后可以考虑让巡检结果可视化。当前版本只输出 Excel 和邮件数据是离线形态。可以加一个简单的 Web 展示层——或者更轻量一点把reports目录里的 Excel 导入到 Grafana 或类似的数据可视化工具里就不需要自己搭前端。支持新厂商设备的扩展点在 netmiko。netmiko 持续在增加新设备的device_type如果自己的设备不在支持列表里可以在ssh_collector.py里做一层兼容手动指定提示符正则。但建议优先升级 netmiko 版本社区维护的适配比自己写的要可靠得多。最后还想多说一句这个项目第一次跑通后我最大的教训是不要一上来就把全部设备都加进巡检清单先从三五台最核心的设备跑两周观察采集数据、告警阈值是不是合理确认没有误报漏报后再逐步扩大范围。从那次之后我每次改配置或代码都会强制先跑一次单设备模式验证通过再放全量执行。自动巡检的本质是减少人工干预但它上线初期反而最需要人工盯着。希望这个项目能帮你把自己的网络状态摸得更清楚。本文还有配套的精品资源点击获取