Python网络设备自动巡检脚本:多厂商支持、异常告警与PDF报告

发布时间:2026/10/16 8:12:03

Python网络设备自动巡检脚本:多厂商支持、异常告警与PDF报告 简介本资源是一套基于Python实现网络设备自动化巡检的轻量级脚本工具包面向IT运维工程师、网络管理员及Python初学者解决大型网络环境中人工巡检效率低、易出错的核心痛点。资源共7个文件含5个INI配置文件分别定义华为、Cisco设备命令集、IP地址列表、账号密码及邮件接收人、1个核心Python脚本autocheck_net.py实现Telnet连接、命令下发与结果采集以及1份README.md说明文档整体仅6KB结构紧凑、开箱即用。已有6139人学习下载体现其在实际运维场景中的广泛认可。读者可直接复用该脚本框架快速适配不同厂商设备掌握Telnet协议交互全流程包括连接管理、身份认证、命令执行与输出解析同时获得可扩展的配置驱动式设计范例便于后续集成定时任务、日志记录或邮件自动报告功能。1. 一个能自动登录、批量采集、异常告警的网络设备巡检脚本运维人不用凌晨爬起来看交换机端口状态了某高校网络中心有 87 台核心/接入层设备覆盖 Cisco、H3C、华为三类厂商日常巡检靠人工 telnet/ssh 登录逐台执行display interface brief或show ip interface brief再肉眼比对 up/down 状态、错误包计数、CPU/内存使用率——平均每人每天耗时 2.3 小时漏检率在 14% 左右尤其凌晨三点的批次。这个 Python 脚本不是玩具 Demo它是一线压测过的真实巡检工程支持多厂商命令适配、连接失败自动重试、设备离线实时微信告警、历史数据存入 SQLite 做趋势分析还能把每日报告自动生成 PDF 发到邮箱。它不依赖任何商业网管平台纯 Python 标准库 Paramiko Netmiko 实现5 分钟就能在你本地跑通第一台设备。如果你手上有几十台设备要盯又不想被半夜的CRC 错误突增报警叫醒这份代码就是你该立刻 clone 下来的「运维后悔药」。2. 环境准备与项目结构解析从 requirements.txt 到 config/devices.yaml 的真实映射2.1 依赖安装为什么只用 pip install -r却要手动补一个包项目根目录下requirements.txt明确列出paramiko3.4.0 netmiko4.3.2 pyyaml6.0.1 jinja23.1.4 weasyprint60.2提示weasyprint依赖系统级库如libpango-1.0.soLinux/macOS 需提前装好pango,cairo,gdk-pixbufWindows 用户直接pip install weasyprint即可但生成 PDF 中文会乱码——必须额外加字体配置见 4.3 节。实际部署时我遇到过netmiko在 Python 3.12 下触发ImportError: cannot import name Mapping from collections。原因netmiko 4.3.2未完全适配 3.12 的 collections 模块重构。血泪经验生产环境统一用 Python 3.11或临时降级 netmikopip uninstall netmiko -y pip install netmiko4.2.22.2 目录结构每个文件都承担明确职责没有“万能 utils.py”network-inspect/ ├── config/ │ ├── devices.yaml # 设备清单IP、厂商、凭据、超时等明文见 3.2 节 │ └── rules.yaml # 巡检规则哪些命令执行、阈值怎么设、告警条件 ├── scripts/ │ ├── main.py # 入口调度设备、并发执行、聚合结果 │ ├── collector.py # 核心采集逻辑登录→发命令→解析输出→结构化 │ ├── parser.py # 多厂商命令输出解析器正则状态机 │ └── reporter.py # 报告生成HTML 模板渲染 → PDF 导出 → 邮件发送 ├── data/ │ ├── db/ # SQLite 数据库存放历史指标device_metrics.db │ └── reports/ # 每日 PDF 报告存档按日期命名 ├── logs/ │ └── inspect.log # 结构化日志JSON 格式方便 ELK 接入 └── requirements.txt注意config/devices.yaml是整个巡检的“设备地图”不是硬编码在 Python 里。这意味着新增一台设备只需改 YAML无需动一行 Python 代码——这是可维护性的分水岭。2.3 devices.yaml 文件详解厂商标识决定命令集和解析逻辑devices: - hostname: core-sw-01 ip: 192.168.10.1 device_type: cisco_ios username: admin password: Pssw0rd123 port: 22 timeout: 10 global_delay_factor: 2 - hostname: access-sw-02 ip: 192.168.10.2 device_type: huawei_vrpv8 username: monitor password: Mon!t0r2024 port: 22 timeout: 15 global_delay_factor: 3 - hostname: firewall-01 ip: 192.168.10.3 device_type: fortinet_fortios username: apiuser password: ApiKey$2024 port: 22 timeout: 20 global_delay_factor: 4关键点device_type必须是 Netmiko 支持的合法值 官方列表 它直接决定底层使用的驱动类如CiscoIosSSH、HuaweiVrpv8SSHglobal_delay_factor控制命令执行间隔避免设备响应慢导致丢包数值越大越保守密码明文风险生产环境应替换为密钥认证或环境变量注入见 3.2 节。3. 核心模块拆解collector.py 与 parser.py 如何协同完成一次“带状态感知”的命令采集3.1 collector.py连接池管理 异常熔断 结构化返回collector.py不是简单地connect → send_command → disconnect。它实现了三层容错连接层重试首次连接失败后按指数退避重试1s, 2s, 4s最多 3 次命令层重试某条命令如display cpu-usage返回空或超时自动重发但仅限 2 次设备级熔断若连续 3 次命令失败标记该设备为unreachable跳过后续命令记录日志并进入告警流程。核心函数collect_device_metrics(device_config: dict)返回结构体{ hostname: core-sw-01, ip: 192.168.10.1, status: success, # or unreachable, partial_failure metrics: { cpu_usage: 32.5, memory_usage: 68.1, interface_stats: [ {name: GigabitEthernet0/1, status: up, in_errors: 0, out_errors: 0}, {name: GigabitEthernet0/2, status: down, in_errors: 12, out_errors: 0} ] }, timestamp: 2024-06-15T02:15:23Z }注意metrics字段是字典嵌套列表不是扁平字符串——这为后续 SQL 存储、阈值判断、API 对接打下基础。3.2 parser.py用正则 状态机解析不同厂商的“非标准”输出不同厂商 CLI 输出格式差异极大Cisco IOSGigabitEthernet0/1 up up 123456789 0H3C ComwareGE1/0/1 UP UP 123456789 0华为 VRPv8GigabitEthernet0/0/1 up up 123456789 0硬写 N 个正则太脆弱。parser.py采用两阶段解析阶段一命令路由根据device_type和命令字符串选择对应解析器def get_parser(device_type: str, command: str) - Callable: if device_type cisco_ios and interface brief in command: return parse_cisco_interface_brief elif device_type huawei_vrpv8 and display interface brief in command: return parse_huawei_interface_brief # ... 其他分支阶段二状态机驱动解析以parse_huawei_interface_brief为例关键逻辑节选def parse_huawei_interface_brief(output: str) - List[Dict]: lines output.strip().splitlines() interfaces [] # 华为输出有表头分隔线需跳过前3行 for line in lines[3:]: # 匹配接口名至少4字符、状态UP/DOWN、协议UP/DOWN、输入字节数、输出字节数 match re.match(r^(\S{4,})\s(UP|DOWN)\s(UP|DOWN)\s(\d)\s(\d), line.strip()) if match: iface_name, phy_status, proto_status, in_bytes, out_bytes match.groups() interfaces.append({ name: iface_name, status: up if phy_status.upper() UP else down, protocol: up if proto_status.upper() UP else down, in_bytes: int(in_bytes), out_bytes: int(out_bytes) }) return interfaces关键参数说明re.match而非re.search确保匹配行首int(in_bytes)强制转数字为后续计算增量做准备phy_status和proto_status分离存储因为某些场景如光纤中断物理层 down 但协议层仍 up。3.3 rules.yaml把“业务语义”从代码中剥离出来config/rules.yaml定义巡检策略而非写死在 Python 里checks: - name: cpu_usage_high command: show processes cpu | include CPU parser: parse_cpu_usage threshold: 85.0 unit: % severity: warning - name: interface_error_rate command: show interface | include errors parser: parse_interface_errors threshold: 10 unit: errors/minute severity: critical - name: memory_usage command: show memory statistics | include Processor parser: parse_memory_usage threshold: 90.0 unit: % severity: warningmain.py加载此文件后动态构建检查任务队列。这意味着运维主管想把 CPU 告警阈值从 85% 降到 75%只需改 YAML不用找开发新增一条检查如temperature只要提供命令和解析函数名5 分钟内上线。4. 运行与调试从单设备测试到全量巡检的完整链路4.1 单设备快速验证绕过配置文件直连调试别一上来就跑全量先用scripts/debug_single.py测试单台设备连通性与命令输出# scripts/debug_single.py from collector import collect_device_metrics from config_loader import load_device_config # 手动构造设备配置绕过 YAML device { hostname: test-sw, ip: 192.168.10.100, device_type: cisco_ios, username: admin, password: Pssw0rd123, port: 22, timeout: 10 } result collect_device_metrics(device) print(fStatus: {result[status]}) print(fCPU: {result[metrics].get(cpu_usage, N/A)}%) print(fInterfaces: {len(result[metrics].get(interface_stats, []))} up, {sum(1 for i in result[metrics].get(interface_stats, []) if i[status]down)} down)运行后观察若报AuthenticationException检查用户名密码、设备是否开启 SSH若卡在send_command超时尝试增大timeout或global_delay_factor若interface_stats为空用netmiko的send_command_timing替代send_command模拟人工回车华为/H3C 常需。4.2 全量巡检执行并发控制与日志追踪执行主程序cd network-inspect python scripts/main.py --config config/devices.yaml --rules config/rules.yaml --concurrency 5--concurrency 5表示最多 5 台设备并行采集避免网络风暴日志默认输出到logs/inspect.log格式为 JSON每行一个事件{timestamp: 2024-06-15T02:15:23Z, level: INFO, device: core-sw-01, event: collection_start} {timestamp: 2024-06-15T02:15:28Z, level: WARNING, device: access-sw-02, event: command_timeout, command: display cpu-usage} {timestamp: 2024-06-15T02:15:35Z, level: INFO, device: firewall-01, event: collection_success, cpu_usage: 42.1}提示用jq快速分析日志Linux/macOSjq select(.event collection_success and .cpu_usage 80) logs/inspect.log4.3 PDF 报告生成中文支持与字体嵌入实操reporter.py使用WeasyPrint渲染 HTML 模板为 PDF。但默认不支持中文——必须显式指定中文字体下载思源黑体免费开源https://github.com/adobe-fonts/source-han-sans解压后将SourceHanSansSC-Regular.otf放入项目根目录fonts/修改reporter.py中HTML(stringhtml_content).write_pdf()调用from weasyprint import HTML, CSS from weasyprint.fonts import FontConfiguration font_config FontConfiguration() css CSS(string font-face { font-family: SourceHanSansSC; src: url(fonts/SourceHanSansSC-Regular.otf); } body { font-family: SourceHanSansSC, sans-serif; } , font_configfont_config) HTML(stringhtml_content).write_pdf( targetfdata/reports/{date_str}_report.pdf, stylesheets[css], font_configfont_config )否则 PDF 中所有中文显示为方框且无法复制文本。5. 常见问题排查5 条真实翻车现场与解法5.1 现象H3C 设备执行display interface brief后返回空列表但手动 SSH 登录能正常看到输出原因H3C 默认开启分页--More--Netmiko 未自动发送空格翻页导致只读取第一页通常是表头解决在devices.yaml中为该设备添加session_log和fast_cli: false并在collector.py的连接参数中显式禁用分页device { # ... 其他字段 fast_cli: False, session_log: flogs/{device[hostname]}_session.log } # 连接后立即执行 connection.send_command(screen-length disable) # H3C 命令 # 或 connection.send_command(terminal length 0) # Cisco 命令5.2 现象华为设备display cpu-usage返回Error: Unrecognized command found at ^ position原因华为 VRPv8 的display cpu-usage需要进入system-view模式才能执行而 Netmiko 默认在用户视图解决修改rules.yaml将命令改为command: system-view\n display cpu-usage\n return并在parser.py的parse_huawei_cpu_usage中用\n分割多行取含CPU的那行。5.3 现象SQLite 写入时报database is locked多个进程同时写device_metrics.db原因Python 的sqlite3模块默认不支持高并发写入--concurrency 5时冲突频发解决改用 WAL 模式 重试机制。在data/db/init_db.py初始化时conn.execute(PRAGMA journal_mode WAL) conn.execute(PRAGMA synchronous NORMAL)并在插入函数中加入重试for _ in range(3): try: cursor.execute(INSERT INTO metrics ..., data) conn.commit() break except sqlite3.OperationalError as e: if database is locked in str(e): time.sleep(0.1) continue raise5.4 现象微信告警发不出日志显示requests.exceptions.ConnectionError: Max retries exceeded原因企业微信/钉钉 Webhook 地址被防火墙拦截或代理设置未生效解决在reporter.py的告警函数中显式传入代理若公司强制走代理proxies {https: http://proxy.internal:8080} if os.getenv(USE_PROXY) else None response requests.post(webhook_url, jsonpayload, proxiesproxies, timeout10)5.5 现象main.py执行后无任何输出进程直接退出原因config/devices.yaml格式错误如缩进用 tab 而非空格PyYAML 解析失败异常被静默吞掉解决在config_loader.py的load_devices()函数开头加强校验try: with open(yaml_path) as f: config yaml.safe_load(f) if not isinstance(config, dict) or devices not in config: raise ValueError(Invalid devices.yaml: missing devices key) return config[devices] except yaml.YAMLError as e: print(fYAML parse error in {yaml_path}: {e}) raise except Exception as e: print(fConfig load failed: {e}) raise6. 二次开发实战如何接入 Prometheus Grafana 做实时指标看板6.1 暴露 HTTP Metrics 端点用 Flask 构建轻量 Exporter不推翻现有架构只新增一个exporter.py模块复用collector.py的采集能力# exporter.py from flask import Flask, Response from collector import collect_device_metrics from config_loader import load_device_config import threading import time app Flask(__name__) # 全局缓存最近一次采集结果线程安全 last_metrics {} last_update 0 def background_collector(): global last_metrics, last_update while True: try: devices load_device_config(config/devices.yaml)[devices] for device in devices[:3]: # 为性能考虑只采前3台 result collect_device_metrics(device) if result[status] success: last_metrics[device[hostname]] result[metrics] last_update time.time() except Exception as e: print(fCollector error: {e}) time.sleep(60) # 每分钟更新一次 # 启动后台采集线程 threading.Thread(targetbackground_collector, daemonTrue).start() app.route(/metrics) def metrics(): if time.time() - last_update 120: # 数据超2分钟视为过期 return No recent data, 503 output [] for hostname, metrics in last_metrics.items(): cpu metrics.get(cpu_usage, 0) mem metrics.get(memory_usage, 0) up_count sum(1 for i in metrics.get(interface_stats, []) if i[status]up) output.append(f# HELP network_device_cpu_usage_percent CPU usage of network device) output.append(f# TYPE network_device_cpu_usage_percent gauge) output.append(fnetwork_device_cpu_usage_percent{{device{hostname}}} {cpu}) output.append(f# HELP network_device_memory_usage_percent Memory usage of network device) output.append(f# TYPE network_device_memory_usage_percent gauge) output.append(fnetwork_device_memory_usage_percent{{device{hostname}}} {mem}) output.append(f# HELP network_device_interface_up_count Number of up interfaces) output.append(f# TYPE network_device_interface_up_count gauge) output.append(fnetwork_device_interface_up_count{{device{hostname}}} {up_count}) return Response(\n.join(output), mimetypetext/plain) if __name__ __main__: app.run(host0.0.0.0, port9101)启动后访问http://localhost:9101/metrics即可看到标准 Prometheus 格式指标。6.2 Prometheus 配置抓取间隔与标签继承在prometheus.yml中添加 jobscrape_configs: - job_name: network-inspect static_configs: - targets: [localhost:9101] metrics_path: /metrics params: format: [prometheus] # 添加设备标签便于 Grafana 过滤 relabel_configs: - source_labels: [__address__] target_label: instance replacement: network-inspect-exporter6.3 Grafana 看板3 个必建 Panel 的查询语句Panel 名称PromQL 查询语句说明CPU 使用率 Top5topk(5, network_device_cpu_usage_percent)按当前值排序接口异常率趋势rate(network_device_interface_up_count[1h])计算每小时接口 up 数变化率设备在线状态count by (instance) (network_device_cpu_usage_percent)返回非零指标的设备数量提示在 Grafana 中为network_device_cpu_usage_percent设置告警规则当value 85持续 5 分钟触发企业微信通知——这比原脚本的“每日一次”更及时。从那以后我每次给新设备加监控都强制走一遍「单设备 debug → YAML 配置 → Prometheus 抓取 → Grafana 验证」四步闭环哪怕只是加一台测试交换机。因为漏掉任意一环线上告警就会变成“已读不回”的静默故障。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/16 8:12:03

MQTT与InfluxDB组合实战:物联网数据采集存储方案

前段时间做了个物联网数据采集的小项目,设备端每隔几秒上报一次温湿度、电量和位置信息,一天下来几百万条数据。一开始团队想用 MySQL 存,结果图表查询慢到让人怀疑人生。这种情况在物联网里太常见了,高频率、按时间流动的传感器数…

2026/10/16 8:12:03

Agent系统中Top K参数的工程化设定方法

1. 这道题不是考算法,是考工程直觉“每周一道 Agent 面试题——Top K 怎么设”,光看标题,很多人第一反应是:又一道 LeetCode 变形题?堆排序?快排分治?滑动窗口?但如果你真这么答&…

2026/10/16 8:12:03

AI助手登录异常复盘:区域性网络故障的Fallback与容灾方案

2024年6月,我所在的项目组经历了一次印象极深的AI助手登录异常。当时正值一个跨平台系统的联调阶段,十几个同事几乎同时发现,常用的AI对话平台开始出现登录页面能打开、但登录请求一直转圈的情况,个别同事甚至被卡到直接报错退出。…

2026/10/16 9:02:23

KBEngine 嵌入式 Python 整数对象 C API(PyLong)权威指南

游戏开发后端 【免费下载链接】kbengine A MMOG engine of server. 项目地址: https://gitcode.com/gh_mirrors/kb/kbengine 点击查看 免费下载 本指南以 KBEngine 仓库内嵌的 CPython 3.7.3 官方文档 kbe/src/lib/python/Doc/c-api/long.rst 为骨架,逐…

2026/10/16 9:02:23

STM32F103_串口通信

STM32F103C8T6 串口通信:轮询 / 中断 / DMA 三种方式,附 Keil 逻辑分析仪测波特率这次做的实验是 STM32 串口(USART)。要求挺全:先用 HAL 库实现最基本的串口收发,再把轮询、中断、DMA 三种方式都过一遍&am…

2026/10/16 9:02:23

【附源码】基于SpringBoot的在线骑行网站(源码+数据库+论文+答辩ppt一整套齐全)java开发springboot+vue框架javaweb,可做计算机毕业设计或课程设计

🙊作者简介:多年一线开发工作经验,分享技术代码帮助学生学习。自有计算机毕设的工作室团队,专注计算机毕设开发、定制、远程、文档编写指导等。 🍅 查看主页更多项目 | 计算机毕设工作室 🍅 🍅 …

2026/10/16 8:57:19

基于MATLAB的多特征融合火灾检测系统GUI实现

控制室里的监控画面往往是最枯燥的,但一旦画面里出现不该有的红色,谁都不敢大意。之前给某个厂区做安防监控需求评估时,对方问能不能用现有摄像头自动识别早期火情,不需要换硬件,最好快速出一版可演示的原型。当时我第…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/16 0:01:11

Cephadm实战指南:Linux系统工程师的生产级Ceph集群部署与排障

简介:本资源是一份完整的Ceph分布式存储系统中文技术文档合集,面向Linux系统运维工程师、云平台架构师及存储方向开发者,帮助读者系统掌握Ceph集群的部署、配置与运维核心能力。文档覆盖对象存储(RGW)、块设备&#xf…

2026/10/16 0:01:11

ITK中SpatialObject几何体系解析:坐标系、变换与管道集成

1. 空间对象的定位:为什么 ITK 需要一套几何描述体系很多刚开始接触 ITK 的朋友,包括我自己,最初都是被它的图像滤波、配准、分割这些“正统”功能吸引进来的。等真正上手做点实际项目,比如把分割出来的器官边界做量化分析、给血管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑