
干网络运维的朋友应该都有过这种经历凌晨两三点被紧急电话叫醒登录交换机一台台排查异常月底要交巡检报告几十台设备一台台敲命令、截图、粘贴进文档。我入行头两年就是这么过来的直到被一个故障逼着学Python写自动化脚本才真正把巡检这件事从体力和眼力活变成了写一次脚本、后面天天复用的工程。这篇文章就来分享我实际打磨过的一套方案用Python批量巡检华为交换机、自动抓取关键状态信息、定时备份配置文件全流程可落地代码可以直接抄。这篇文章适合两类读者一类是刚接触网络自动化的运维新人想找一条从零开始的可执行路径另一类是已经在用手工巡检、想给日常工作减负的工程师。我会把环境准备、脚本设计、核心代码、常见坑全部拆开讲尽量说人话不讲虚的。1. 巡检需求梳理与整体方案设计1.1 手工巡检的痛点与自动化收益先说痛点。手工巡检华为交换机最常见的做法是SecureCRT或Xshell登录设备然后敲display version、display cpu-usage、display memory-usage、display interface brief这些命令肉眼判断状态正常与否再把输出截图或复制到Excel里。听起来不复杂但一旦设备数量超过二十台问题就来了。我统计过一个真实场景一台设备完整巡检一遍大概需要8到12分钟包括登录、逐条敲命令、等待回显、人工判读、记录结果。二十台设备就是三四个小时而且中间容不得一点打扰否则不知道敲到哪台哪条命令了。更麻烦的是月底要汇总本月所有设备的巡检报告如果你没有在巡检当场做好记录回看截图和日志简直是一场灾难。自动化巡检解决的正是这两个核心痛点一是把人从重复敲命令中解放出来二是让巡检过程留痕每一次执行的结果都自动落盘随时可以回溯。我后来把这套脚本跑起来之后同样二十台设备全部巡检加配置备份总耗时不超过两分钟而且结果格式统一、时间戳完整无论是自检还是被审计抽查都能直接拿出数据说话。1.2 技术选型Netmiko还是Paramiko选型是很多人第一个卡住的地方。做网络设备SSH自动化绕不开Paramiko和Netmiko这两个库。Paramiko是一个底层的SSH协议实现库它做的事情是建立SSH连接、执行命令、读取回显至于命令的交互逻辑、分页处理、设备差异适配全都要你自己写。好处是灵活坏处是工作量很大。我记得第一次用Paramiko连华为设备被---- More ----分页卡了半天后来才知道要发送空格键翻页或者用screen-length 0 temporary临时关闭分页。Netmiko是在Paramiko之上封装了一层专门为网络设备设计的库。它对主流厂商设备做了适配比如Cisco、华为、H3C、Juniper等连接后会自动处理分页、提示符匹配、设备类型差异。我用Netmiko写华为设备的脚本基本不用操心底层交互细节。比如send_command方法会自动发送screen-length 0 temporary这类命令来关闭分页这对巡检脚本来说非常重要。所以我的建议很直接巡检和备份配置的脚本直接用Netmiko。只有当你需要实现Netmiko不支持的某种特殊交互协议比如某些专有协议或复杂的CLI菜单跳转时才值得回到Paramiko自己造轮子。1.3 整体架构设计在动手写代码之前我强烈建议先把整个巡检流程画一遍。不需要多复杂关键是把输入、处理、输出理清楚。我的方案分四层第一层是设备清单层。用一个YAML文件统一管理所有被巡检设备的IP、用户名、密码、设备名称脚本运行时读取这个文件。设备增删改只动YAML文件不碰代码。第二层是巡检执行层。脚本通过Netmiko并发连接各台设备依次下发巡检命令集合收集输出。这里的核心设计是命令集合与设备解耦也就是说巡检命令放在一个列表里方便随时增删。第三层是结果处理层。对收集到的原始输出做解析和规整。比如从CPU使用率输出里提取百分比从接口状态里过滤出非Up的接口生成结构化数据。第四层是存储与报告层。把巡检结果、配置备份文件按设备、日期归档生成可读的文本报告或Excel表格并结合定时任务实现无人值守巡检。这个架构的好处是每一层都可以独立替换。比如今天用文本报告明天想换成Excel只需要改第四层设备多了想加并发也只需要改第二层的线程逻辑其他部分完全不用动。2. 环境准备Python、依赖库与交换机侧配置2.1 Python与依赖库安装运行环境这块我在Windows和Linux上都跑过建议先确认Python版本。Netmiko比较新的版本对Python 3.8以上支持得都很好我个人推荐Python 3.8到3.11之间的版本稳定且兼容性好。Windows下安装Python没什么好说的去Python官网下载安装包记得在安装向导第一步勾选Add Python to PATH这是新手最容易漏掉的一步。装完之后打开命令行验证python --version pip --version如果提示pip不是内部或外部命令大概率是Python没有加入环境变量重新安装并勾选PATH选项即可。接下来安装依赖库。我的项目依赖总共就三个pip install netmiko pyyaml如果后面要生成Excel报告再加一个pip install openpyxl有人可能会问为什么不用pandaspandas做表格处理确实强大但结合openpyxl我在实践中更喜欢直接用openpyxl或csv标准库因为巡检报告格式相对固定没必要引入一个重量级依赖。当然如果你本来就在用pandas用它做数据分析也是可以的纯看个人习惯。VSCode是我推荐的调试工具装好Python插件后在settings.json里指定Python解释器路径即可。用命令行跑脚本也没问题我自己生产环境里都是直接用crontab或Windows任务计划程序调脚本根本不依赖IDE。2.2 华为交换机侧的准备脚本连不上设备八成不是代码问题而是交换机侧没有开放SSH服务。华为设备以VRP系统为主启用SSH管理的大致配置如下sys stelnet server enable ssh user admin ssh user admin authentication-type password ssh user admin service-type stelnet aaa local-user admin password cipher Huawei123 local-user admin service-type ssh local-user admin privilege level 15 quit这里有几个细节。第一local-user admin privilege level 15一定要配否则即使登录成功执行display current-configuration等命令也可能因为权限不足被拒绝。第二如果交换机跑了多版本VRPV200R005等常见版本命令细节可能有细微差异配置时可以通过display version确认具体版本再对照手册。另外建议在交换机上创建一个专门的巡检账号权限给到最低但足以读取配置和状态即可不要直接拿管理员账号跑脚本。原因很实在命令行有审计日志巡检账号被设备记录后后续追溯某条配置变更是谁做的不会被巡检任务干扰。而且万一密码泄露巡检账号的破坏力远比管理员小。还有一个容易被忽略的点巡检账号的密码如果频繁变动脚本设备清单里的密码也要同步更新。我建议把密码尽量做加密存储或者在运行时从外部参入密文件读取别把明文密码硬编码在脚本里。我的YAML文件里是明文存储的但这只适用于内部可信环境如果条件允许用Python的getpass交互输入或者接入公司已有的密钥管理系统更稳妥。2.3 设备清单的YAML设计设备清单文件devices.yaml大概长这样global: timeout: 30 connection_timeout: 15 switches: - name: core-sw-01 host: 192.168.1.1 username: inspect password: Inspect2024 device_type: huawei - name: access-sw-02 host: 192.168.1.2 username: inspect password: Inspect2024 device_type: huawei - name: core-sw-03 host: 192.168.1.3 username: inspect password: Inspect2024 device_type: huawei把device_type写进每个设备条目是为了将来兼容其他厂商设备预留的扩展位。等你哪天从华为换成别的品牌或者网络里混着多厂商设备这个字段就会发挥巨大作用。timeout参数也值得一提华为设备在CPU高负荷时命令回显会很慢默认的20秒超时经常不够我统一设置成了30秒。3. 巡检脚本核心实现3.1 连接设备与命令下发直接用Netmiko的示例能跑通但生产环境建议封装一层比如我写的connect_switch函数from netmiko import ConnectHandler def connect_switch(device): 建立SSH连接 try: connection ConnectHandler( device_typedevice.get(device_type, huawei), hostdevice[host], usernamedevice[username], passworddevice[password], timeoutdevice.get(timeout, 30), conn_timeoutdevice.get(connection_timeout, 15) ) return connection except Exception as e: print(f[ERROR] {device[name]} 连接失败: {str(e)}) return Nonedevice_type填huaweiNetmiko会自动对华为VRP的命令交互做适配包括关闭分页和提示符匹配。调用端就很简单了conn connect_switch(device) if conn is None: continue output conn.send_command(display version, expect_stringr)这里有个小坑send_command可以不要expect_string但如果你用了必须确保华为的提示符匹配正确。华为默认用户视图提示符是设备名系统视图是[设备名]。不同模式下提示符格式不一样Netmiko内部会处理但如果自己写正则容易踩这个坑。3.2 日常巡检命令与结果解析巡检命令集合我定义成常量INSPECT_COMMANDS [ (version, display version), (device, display device), (cpu_usage, display cpu-usage), (memory_usage, display memory-usage), (interfaces, display interface brief), (logs, display logbuffer) ]每台设备执行完这六条命令把输出按设备名和命令名存成文件同时从关键输出里提取结构化状态字段做健康度判断。以CPU使用率为例华为display cpu-usage的输出格式大致是CPU Usage : 12% Max: 35%用正则提取即可import re def parse_cpu_usage(raw_output): match re.search(rCPU Usage\s*:\s*(\d)%, raw_output) return int(match.group(1)) if match else -1采集接口状态也是一样display interface brief的输出里每个接口一行以up或down标记状态。写一个过滤函数专门找出状态为down的接口def find_down_interfaces(interface_output): down_interfaces [] for line in interface_output.splitlines(): if re.search(r\sdown\s, line) and GE in line or XGE in line or Eth in line: down_interfaces.append(line.split()[0]) return down_interfaces如果不想自己写正则也可以用TextFSM把华为命令输出解析成结构化表格。TextFSM的工作方式就是写一个模板文件描述输出格式然后用textfsm库解析。我最初也尝试过但后来发现华为的命令输出在不同版本上字段位置有差异模板维护成本高。单条命令用正则批量状态判断完全可以覆盖没有必要为了标准化而增加复杂度。3.3 配置备份的完整实现配置备份是脚本的另一半功能个人认为它的重要性甚至超过实时巡检。因为巡检是看当前状态而配置备份解决的是出问题之后能还原。华为设备备份配置最常用的命令是display current-configuration注意这条命令的输出可能非常长核心交换机配置几千行很正常。Netmiko的send_command默认会处理分页但输出量大时需要设置超时时间更长。我实测一台配置三千多行的核心交换机完整回显时间大约5到10秒所以timeout一定要给足。备份部分的代码def backup_config(conn, device, backup_dir): 备份交换机配置到本地 timestamp datetime.datetime.now().strftime(%Y%m%d_%H%M%S) config conn.send_command(display current-configuration, timeout60) os.makedirs(backup_dir, exist_okTrue) filename os.path.join(backup_dir, f{device[name]}_config_{timestamp}.txt) with open(filename, w, encodingutf-8) as f: f.write(config) lines config.count(\n) print(f[OK] {device[name]} 配置备份完成, 共 {lines} 行, 文件: {filename}) return filename这里有几个细节值得多说一句。第一编码统一用utf-8。华为的配置里可能带一些特殊字符比如中文描述、BOM标记。用gbk或默认编码可能导致文件无法被其他工具正常读取。不过有个例外如果你在Windows上用记事本打开备份文件记事本默认按ANSI解析UTF-8文件里的中文注释可能显示乱码。我后来统一用VSCode或Notepad打开就没这个问题了。第二备份文件名里带上设备名和时间戳这样每次备份都不会覆盖上一个版本天然形成历史版本链。当需要回滚时直接找各时间点的备份做diff就行。第三配置备份和巡检最好在同一个连接会话里完成。先跑巡检命令最后执行display current-configuration。这样可以减少频繁建立SSH连接带来的开销和潜在风险。关于配置一致性校验我后面会专门讲这里先按下不表。3.4 批量巡检与执行效率优化单台设备巡检跑通后批量就是顺理成章的事。最朴素的写法是for循环逐台设备连接、巡检、备份二十台设备按每台10秒算就需要两百多秒。这个速度勉强能接受但如果你管理五十台以上的设备建议还是加上并发。我用concurrent.futures.ThreadPoolExecutor做并发from concurrent.futures import ThreadPoolExecutor, as_completed def inspect_one_device(device, backup_dir): 单台设备巡检备份的完整流程 result { name: device[name], status: SKIPPED, details: {} } conn connect_switch(device) if conn is None: return result try: report_lines [f {device[name]} 巡检报告 ] report_lines.append(f生成时间: {datetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S)}) for label, command in INSPECT_COMMANDS: try: output conn.send_command(command, timeout30) report_lines.append(f\n---- {label} ----) report_lines.append(output) if label cpu_usage: result[details][cpu] parse_cpu_usage(output) elif label interfaces: down find_down_interfaces(output) result[details][down_interfaces] down except Exception as e: report_lines.append(f\n[ERROR] 命令 {command} 执行失败: {str(e)}) backup_filename backup_config(conn, device, backup_dir) report_lines.append(f\n配置备份: {backup_filename}) # 写巡检报告 report_filename os.path.join(backup_dir, f{device[name]}_report_{datetime.datetime.now().strftime(%Y%m%d_%H%M%S)}.txt) with open(report_filename, w, encodingutf-8) as f: f.write(\n.join(report_lines)) result[status] SUCCESS except Exception as e: result[status] ERROR result[details][msg] str(e) finally: conn.disconnect() return result并发调用def run_batch_audit(devices, backup_dir, max_workers5): results [] with ThreadPoolExecutor(max_workersmax_workers) as executor: futures [executor.submit(inspect_one_device, device, backup_dir) for device in devices] for future in as_completed(futures): result future.result() results.append(result) print(f[{result[status]}] {result[name]} - {result[details]}) return resultsmax_workers5是我实测过的推荐值。并发开太多会有两个问题一是你所在网络出口的并发SSH连接数有限二是设备端如果同时涌入太多连接部分型号的交换机CPU会飙升反而影响命令响应。五到八个并发是一个相对安全的区间。3.5 巡检结果的整体归档归档目录结构我推荐这样组织backup/ 2024-06-15/ core-sw-01_config_20240615_030001.txt core-sw-01_report_20240615_030001.txt access-sw-02_config_20240615_030002.txt access-sw-02_report_20240615_030002.txt 2024-06-16/ ...按日期建目录有两个好处一是每天巡检结果一目了然二是审计时按时间线翻目录非常顺手。我还习惯在处理层把CPU使用率、接口Down数量这些关键指标汇总输出到一个简单的CSV文件里方便月底做趋势分析import csv def write_summary_csv(results, date_str): filename fsummary_{date_str}.csv with open(filename, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([设备名, CPU使用率(%), Down接口数, 状态]) for r in results: details r.get(details, {}) down_ifs details.get(down_interfaces, []) writer.writerow([ r[name], details.get(cpu, N/A), len(down_ifs), r[status] ])有了这个CSV月底回汇总时直接打开Excel透视表就能看趋势再不用翻一堆截图了。4. 定时任务部署与无人值守脚本写好了巡检却不能每次都手动执行那样跟手工巡检没本质区别。必须交给定时任务。4.1 Linux下crontab部署Linux服务器上跑用crontab是最省事的# 每天凌晨3点执行巡检 0 3 * * * cd /opt/switch_inspect /usr/bin/python3 inspect_switch.py /var/log/switch_inspect.log 21两个细节。第一crontab里一定要写Python解释器的绝对路径因为crontab的PATH环境变量很干净直接写python3可能找不到解释器这是新手必踩的坑。第二日志重定向一定要加否则脚本跑了没有日志出问题只能干瞪眼。表示追加21把标准错误也重定向到同一个文件。日志文件建议按天轮转。Linux自带的logrotate配起来很快或者更简单的方式是在脚本内部用logging模块按天滚动。4.2 Windows下任务计划程序部署Windows环境用任务计划程序即可。在创建基本任务向导里设置每天固定时间触发操作里选启动程序程序填写Python的完整路径参数填脚本的完整路径起始于填写脚本所在目录。我实际用Windows部署时踩过两个坑一是Python解释器路径带空格会报错最好把路径加双引号二是脚本里如果有用相对路径读取YAML文件的地方必须在任务里把起始于设置为脚本目录否则脚本运行时的工作目录可能不是脚本所在目录读不到devices.yaml。4.3 无人值守后的健康检查定时任务跑起来之后需要有一个检查检查脚本的机制。我推荐每天早上看一眼当天的巡检汇总CSV如果发现某台设备状态异常或者整个批处理超时再人工介入。更进一步可以在脚本末尾加一段简单逻辑如果某台设备连续两次巡检失败就通过钉钉群机器人或邮件发送告警。这一块要看你的告警通道代码本身也就是在run_batch_audit返回结果里遍历一下status ERROR的设备做时间戳比对不算复杂。我这里不贴具体代码因为告警通道各自环境差别太大。5. 常见问题与排错实录做了这么久把脚本从零跑通的人大多会卡在几个同样的问题上。我把高频问题整理成了一张排查表然后再挑几个细说。问题现象可能原因解决思路SSH连接超时交换机未开启SSH/网络不通先确认stelinel server enable再用telnet或SSH客户端手工测试认证失败用户名密码错误/AAA配置问题确认local-user是否配置service-type ssh权限级别是否足够命令回显截断分页未关闭或timeout太短检查Netmiko是否自动处理分页调大send_command的timeout中文乱码字符编码不一致保存文件和脚本统一使用utf-8查看时用UTF-8解码备份文件内容为空命令被设备拒绝或连接中断手工执行display current-configuration确认权限并发报错过多线程数太多设备处理不过来调低max_workers观察设备CPU5.1 SSH登录失败的排查思路SSH登录失败我第一反应不是看脚本而是先用命令行手工试连ssh admin192.168.1.1如果手工也连不上问题就在交换机侧。最常见的原因是stelnet server enable没开或者AAA里没有为SSH用户配置service-type。还有一种情况交换机同时启用了Telnet和SSH但SSH接入VTY口的权限规则限制了访问源。如果你之前按网上教程配置过ACL只允许某个管理网段访问注意确认脚本所在机器的IP在放行范围内这就是很多朋友搜华为交换机怎么用acl设置唯一管理终端登录会遇到的场景。如果手工能连上、脚本连不上那就要检查Netmiko的设备类型是否填错。填了huawei之外的值比如hp_comware或cisco_ios提示符处理方式不同也会导致认证流程异常。5.2 命令回显分页截断华为设备默认输出超过一屏会进入分页模式提示---- More ----。如果不等分页继续输入下一个命令命令会像乱码一样夹杂在回显里。Netmiko对华为设备的处理方式是自动发送命令关闭分页它在连接建立时一般会执行screen-length 0 temporary。但有两个例外情况会导致分页问题一是设备版本较老screen-length 0 temporary在用户视图不可用需要在系统视图下执行screen-length 0二是你直接用了底层paramiko通道。我的建议是在巡检脚本连接后可以先主动发一条screen-length 0 temporary即使重复执行也无副作用。另外要注意display logbuffer这类命令输出可能特别长如果设备日志量大回显时间会明显变长。我遇到过一台设备日志缓冲区满了display logbuffer回显花了近30秒所以命令执行超时要给足别用默认的8秒。5.3 中文乱码问题华为交换机里常有中文描述的接口比如上联-核心交换机-01。备份下来的配置打开一看全是乱码当时我排查了半天最后发现是编码问题。SSH通道传输字节流Python拿到字节流之后需要用正确的编码解码。华为设备默认的编码多为GBK或GB2312而Netmiko在读取时默认尝试UTF-8解码。解决方式是在连接参数里指定编码connection ConnectHandler( ..., encodinggb2312, )但注意加了encodinggb2312之后输出结果里的中文能正常显示而写出文件时又要统一用UTF-8存盘。我的做法是通道解码用gb2312写文件用utf-8这样既保证了屏幕打印正常也保证了备份文件在跨平台工具上可读。如果你所在的网络环境里设备普遍没有中文描述不配置encoding也没问题但一旦有一台有中文描述就会炸所以建议一开始就加上。5.4 配置备份一致性校验配置备份出来以后怎么确认它和交换机上实际运行的配置一致毕竟如果备份过程中连接中断配置文件缺失一半事后回滚会出大问题。我常用的校验方式有三种按可靠性从低到高排第一是行数对比。记录执行display current-configuration的回显行数和备份文件实际行数对比不一致则说明被截断。这个方法最粗糙但最容易实现。第二是头尾标记校验。华为配置输出的开头是#注释行或者sysname结尾是return。检查备份文件是否包含这两类关键标记如果缺失大概率不完整。第三是双命令对比。除了display current-configuration再执行一次display saved-configuration两条命令的输出做diff差异过大说明有未保存的配置变更。实际上把这三招组合用更靠谱。我在脚本里做了两层校验行数与return关键字检测。足以应对绝大多数备份失效场景def verify_backup(filename, raw_output): with open(filename, r, encodingutf-8) as f: content f.read() raw_lines raw_output.splitlines() file_lines content.splitlines() checks { 行数一致: len(raw_lines) len(file_lines), 包含return: return in content, 非空文件: len(file_lines) 0 } return all(checks.values()), checks6. 一些额外的实操建议脚本能跑通之后有几个细节我是在长期使用中慢慢悟出来的分享给你。巡检命令一定要按需增减。上面写的六条是我在核心交换和接入交换场景中总结出的基础集合。如果你想关注DHCP地址池的剩余情况就加一条display ip pool想关注ACL命中计数就加display acl all。华为三层交换机的运维场景千差万别命令集合保持可配置化你会省很多改代码的功夫。备份文件要定期清理。每天一次全量备份一台设备一年就是365个文件十台设备几千个文本文件磁盘占用虽然不大但目录会变得极其难翻。我在脚本里加了一段逻辑保留最近30天的备份更早的压缩成zip归档。这样既不丢失历史追溯能力又避免目录爆炸。务必用独立巡检账号。这个前面说过但值得重复一次。不仅是为了安全隔离也是为了审计清洗。有一次客户做配置变更审计调出命令行日志看到大量巡检命令的record第一反应是有人恶意操作。后来排查发现是巡检脚本利用管理员账号跑出来的排查成本非常高。用独立账号就不会有这种乌龙。最后聊一个习惯层面的体会。自动化巡检脚本不是写一次就完事的设备型号更新、VRP版本升级、网络拓扑调整都会让脚本需要微调。我的做法是每个月花半天时间打开当月的巡检汇总CSV和备份目录把设备状态是否有异常趋势和脚本执行成功率都过一遍。把巡检脚本本身当成一个需要持续维护的内部小产品来对待。很多运维朋友的自动化脚本跑了一个月就变成了垃圾代码不是因为当初写得差而是因为没有跟进设备侧的持续变化。我在实际使用中还发现巡检自动化这件事最好的切入角度不是我要学Python而是我要解决下周一之前交不出巡检报告的难题。带着具体问题去写脚本比对着教程学十天语法都有效。如果你手头正好有几台华为交换机要巡检别犹豫按这个思路先把单台设备的备份跑通再批量扩展一周时间就能把这项能力变成自己日常工具箱里的标配。