1. 写在前面这个备份脚本解决了我多年的心头病干了几年网络运维最烦的事不是割接不是排障而是给交换机做配置备份。特别是赶上版本升级、设备上线或者半年一次的巡检十几台、几十台设备一台台登录进去敲display current-configuration华为/H3C或者show running-config思科再把输出一屏屏复制出来存成文件。运气好半小时搞定运气不好碰上设备响应慢、终端翻页卡顿折腾一上午都是常事。更要命的是手动备份经常漏设备、漏日期等真出了故障想回滚翻遍电脑也找不到一周前的配置那感觉真是“欲哭无泪”。所以我就琢磨着写个Python脚本把这套重复劳动自动化。今天这篇文章就是把我的完整思路和代码分享出来从一个网络工程师的角度手把手带你写一个能直接用在生产环境的交换机配置备份脚本。这篇文章适合谁看如果你是网络工程师、运维工程师或者正在往网工方向转行、想学Python但找不到实际落地场景的朋友那这篇文章就是给你准备的。我不讲那些虚头巴脑的语法直接把能干活、能备份、能定时跑的完整代码怼给你再把我踩过的坑一个个指出来。我这个脚本的核心思路其实很简单用Python的netmiko库模拟SSH登录交换机自动执行查看配置的命令然后把输出内容保存成带时间戳的文本文件。整个过程不需要额外安装什么重型软件一台普通的电脑、一个Python环境就够了。而且脚本是跨厂商设计的思科、华为、H3C、锐捷这些主流设备都能用你只需要改一下设备类型和设备列表就行。我先说结论这套方案我实际跑了一年多稳定备份了上百台设备没出过一次岔子。接下来我按“设计思路→环境准备→代码拆解→完整脚本→问题排查”的顺序一步一步给你讲透。2. 整体设计思路为什么选Python为什么用netmiko2.1 配置备份这活儿自动化之前先想清楚三件事写脚本之前我先列了一下需求清单。配置备份看着简单但真正做起来有几个“隐性需求”很容易被忽略批量执行不是一台两台而是几十台上百台设备要能一次性连一圈自动跑完。可追溯备份文件必须带上日期时间这样出问题的时候才能找到对应时间点的配置。跨厂商兼容公司网络设备不可能只有一个牌子至少得兼容思科和华为这两大体系。异常处理总会有几台设备密码变了、网络不通、SSH连不上脚本不能因为一台设备报错就中断全部备份。执行记录每次备份跑了哪些设备、哪些成功了、哪些失败了得有个日志不然还是两眼一抹黑。这几点想清楚之后“用Python写脚本”这个选择就变得非常自然。原因很简单Python的第三方库生态太丰富了做网络自动化有几个现成的库可以直接用不用自己从零造轮子。2.2 为什么不用Shell脚本而用Python我知道很多网工的第一反应是备份配置而已用Shell脚本加expect不就搞定了吗确实如果你管理的设备就那么三五台而且都是同一个厂商用Shell脚本确实够用。但一旦设备数量多起来、品牌杂起来Shell脚本处理交互式SSH就会比较痛苦——你要自己处理登录提示符、密码提示、分页符这些乱七八糟的东西脚本会越写越复杂。Python这边就清爽多了。尤其是netmiko这个库它把SSH连接、登录交互、命令发送、输出读取这些底层细节全部封装好了。你只需要告诉它“设备IP是什么、用户名密码是多少、设备是什么牌子”然后说“帮我执行这条命令”剩下的活它全包了。netmiko底层用的是paramiko一个Python的SSH协议实现库但它比直接用paramiko要友好一百倍——paramiko需要你自己处理shell交互而netmiko把这些都给你简化了。我早期的脚本是用paramiko写的后来发现对厂家的适配、分页处理、超时重试这些都要自己做代码越写越长。换了netmiko之后核心逻辑从两百行缩到了几十行。2.3 脚本的核心流程连接-执行-保存整个脚本跑起来的流程用一个词概括就是“流水线”。我画了一张逻辑图在脑子里这里用文字给你描述一下读取设备清单IP地址、用户名、密码、设备类型。循环遍历每一台设备建立SSH连接。连接成功后自动进入设备的特权模式如果需要的话。执行“显示当前配置”的指令把输出内容拿到手。把输出内容写入一个以设备IP加日期命名的文本文件。无论成功还是失败都记录一条日志。继续处理下一台设备直到全部跑完。这套流程每台设备大约耗时10到20秒主要取决于设备响应速度一百台设备大概二三十分钟就能全部备份完。你可以把它挂到计划任务里凌晨自动跑第二天早上来上班所有配置都已经安安静静躺在文件夹里了。3. 环境准备与工具选型别在这第一步就翻车3.1 Python安装和pip的坑我帮你提前踩平有好多网工朋友跟我说“我看你写的代码挺好的但我连Python都没装。”这套脚本对环境要求确实不高但Python环境装不好后面全是坑。Python下载安装这步我就不细说了去Python官网下载对应你操作系统的安装包一路Next就行。但有两点我必须强调第一安装的时候一定要勾选“Add Python to PATH”不勾的话装完你在命令行敲python会提示“无法将‘python’项识别为cmdlet、函数、脚本文件或可运行程序的名称”。这就是网上搜“python安装教程”的人踩得最多、问得最多的一个坑。第二安装完Python之后打开命令行窗口输入python --version如果能正常输出版本号说明Python本体没问题。接下来再输入pip --version检查pip是否可用。如果你的电脑上提示“pip无法识别”那多半是PATH环境变量里没加Scripts目录。解决办法很简单手动把C:\Users\你的用户名\AppData\Local\Programs\Python\Python311\Scripts这个路径加到系统环境变量的Path变量里然后重新打开命令行窗口。很多初学者拿到Python之后装第三方库装不上基本都是卡在这里。3.2 netmiko库为什么它是网工自动化首选Netmiko是思科的一位工程师Kirk Byers开发的开源库专门用来简化网络设备的SSH连接和配置操作。它在paramiko的基础之上封装了大量网络工程师常用的功能内置了几十种主流厂商设备的交互模型思科IOS、Nexus、华为VRP、H3C Comware、锐捷、Juniper等。自动处理登录后的分页符--More--这种翻页提示。自动检测设备提示符等命令输出完了再返回。提供了简洁的API比如send_command()发命令、send_config_set()下发配置。安装netmiko只需要一行命令pip install netmiko它会自动把paramiko、textfsm、ntc_templates这些依赖库一起装上。等命令跑完你输入pip list能看到netmiko和它的依赖就说明安装成功了。我用netmiko一年多的感受是这个库对网络工程师极其友好。你不需要是编程高手只需要会写for循环和if判断就能写出非常专业、非常可靠的自动化脚本。3.3 验证设备连通性连不上写什么都白搭在写脚本之前我强烈建议你先手动测一下几台设备确保设备已经开启了SSH服务并且你的电脑能通过SSH登录上去。测试方法很简单直接在命令行敲ssh 用户名设备IP地址如果设备返回密码输入提示说明SSH服务正常。如果提示Connection refused说明设备没开SSH需要去设备上手动开启如果提示Connection timed out则说明是网络可达性的问题该查路由查路由该查防火墙查防火墙。这里顺便提一嘴有些设备默认只开了Telnet没开SSH。虽然netmiko也支持Telnetdevice_type填cisco_ios_telnet就行但SSH是加密的从安全性角度考虑我都建议在设备上把SSH配上配好之后生产环境直接用SSH。4. 核心代码拆解每一行都在干什么4.1 设备清单的定义别把密码直接写死在代码里干净的做法是把设备信息写在一个devices列表里每个设备是一个字典。你可以直接改这个列表来增删设备非常方便。devices [ { device_type: huawei, ip: 192.168.10.1, username: admin, password: Admin123, secret: Priv456, # 如果需要进入特权模式思科设备这里填enable密码 }, { device_type: cisco_ios, ip: 192.168.10.2, username: netadmin, password: Net123, secret: Enable789, }, ]这里重点解释几个字段device_type这个字段决定了netmiko用哪一套交互逻辑来处理设备。常用的有huawei、cisco_ios、h3c、ruijie、cisco_nxos等。写错了很大概率会卡在登录阶段。ip设备的IP地址脚本连不上会报错所以务必确认准确。username / passwordSSH登录凭据。secret思科设备进入特权模式时需要输入的enable密码。华为/H3C设备如果登录用户直接有权限执行命令这个字段可以留空。关于密码管理我一般会在脚本里用os.environ从环境变量读密码或者干脆把密码字段用getpass在运行时手动输入。生产环境里建议至少不要把密码硬编码在脚本里万一脚本被人看到等于把整个网络设备的登录凭据都交出去了。4.2 连接设备与执行命令netmiko的核心三板斧接下来是脚本的心脏——连接设备、执行命令、返回结果。我用一个函数来单独封装方便复用和排错。from netmiko import ConnectHandler from datetime import datetime import os def backup_device(device): ip device.get(ip) backup_dir backup_configs os.makedirs(backup_dir, exist_okTrue) # 生成带时间戳的文件名192.168.10.1_20250115_083000.cfg timestamp datetime.now().strftime(%Y%m%d_%H%M%S) filename f{backup_dir}/{ip}_{timestamp}.cfg try: # 建立SSH连接 conn ConnectHandler(**device) print(f[OK] 已连接设备 {ip}) # 进入特权模式如果设备配置了secret if device.get(secret): conn.enable() # 根据设备类型选择查看配置的命令 if device[device_type] huawei: command display current-configuration else: command show running-config # 发送命令并获取输出 output conn.send_command(command, read_timeout30) # 写入文件 with open(filename, w, encodingutf-8) as f: f.write(f# 设备: {ip}\n) f.write(f# 备份时间: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)}\n) f.write(# * 60 \n\n) f.write(output) print(f[OK] 设备 {ip} 配置已保存到 {filename}) conn.disconnect() return True except Exception as e: print(f[ERROR] 设备 {ip} 备份失败: {e}) return False这一段代码是核心每一块我都说下ConnectHandler(**device)这行是把device字典里的所有键值对直接作为参数传给ConnectHandler。收到设备信息、完成TCP和SSH握手之后函数会返回一个连接对象后续所有操作都是通过这个conn对象来进行的。conn.enable()的作用是让netmiko自动进入设备的特权模式。对思科设备来说登录进去默认是用户模式很多命令执行不了必须enable进入特权模式才行。对于华为设备如果你的账号本身就是管理员权限不执行这步也没问题。conn.send_command(command, read_timeout30)是真正执行命令的地方。netmiko会自己处理分页符等到命令输出全部结束才返回完整的文本。这个read_timeout30参数我建议加上它的含义是“等待命令输出超时时间”防止个别设备响应太慢导致脚本卡死。30秒基本够用如果你们设备性能差可以调大到60。4.3 文件命名与归档别小看了这个细节备份出来的文件名我用了IP_年月日_时分秒.cfg这种格式。我为什么不用单纯的日期因为同一天如果你手动跑了两次脚本第二次会直接覆盖第一次的文件。加上了时分秒之后每次备份都是独立文件不会互相覆盖。后缀名用.cfg还是.txt其实无所谓主要看个人习惯。我习惯用.cfg这样和网工日常接触的配置文件名一致。如果你希望备份文件能被更多编辑器识别用.txt也行。所有备份文件会统一放在脚本同目录下的backup_configs文件夹里。这里有个小优化os.makedirs(backup_dir, exist_okTrue)的意思就是“如果目录不存在就创建存在就不管”。这样即使你换了一台机器跑脚本也不用担心目录不存在导致报错。4.4 循环遍历所有设备一台失败不影响其他有了backup_device这个函数后面再遍历设备列表就很简单了success_count 0 total_count len(devices) for device in devices: result backup_device(device) if result: success_count 1 print(f备份完成成功 {success_count}/{total_count} 台。)这里的核心思路是逐台设备独立处理。每台设备都在函数内部做了异常捕获try...except所以即使某些设备连接失败脚本也不会中断而是会继续处理下一台。等全部跑完之后通过成功计数你就知道这次整体备份的情况。生产环境里我还会加一个细节把每台设备备份的成败结果追加到一个日志文件里。这样就算第二天来看结果也能知道昨天哪些设备失败了不用傻傻盯着命令行窗口。with open(backup_log.txt, a, encodingutf-8) as log: log.write(f{datetime.now()} | 设备 {device[ip]} | 成功\n) # 或 失败5. 完整脚本参考下载就能用改改就能跑5.1 完整脚本代码前面拆解了各个模块这里我把完整脚本贴出来。这是我实际在用的版本去掉了敏感信息逻辑完全一致。你保存成backup_switch.py安装好依赖改一改devices列表里的设备信息就能直接跑。#!/usr/bin/env python3 # -*- coding: utf-8 -*- 交换机配置备份脚本 适用设备: 华为 / H3C / 思科 (支持netmiko的所有设备类型均可) from netmiko import ConnectHandler from datetime import datetime import os # 配置区 BACKUP_DIR backup_configs LOG_FILE backup_log.txt devices [ { device_type: huawei, ip: 192.168.10.1, username: admin, password: Admin123, secret: , }, { device_type: cisco_ios, ip: 192.168.10.2, username: netadmin, password: Net123, secret: Enable789, }, ] # def write_log(message): 写日志文件 with open(LOG_FILE, a, encodingutf-8) as f: f.write(f{datetime.now().strftime(%Y-%m-%d %H:%M:%S)} | {message}\n) def backup_device(device): 备份单台设备返回True表示成功 ip device.get(ip) os.makedirs(BACKUP_DIR, exist_okTrue) timestamp datetime.now().strftime(%Y%m%d_%H%M%S) filename os.path.join(BACKUP_DIR, f{ip}_{timestamp}.cfg) try: conn ConnectHandler(**device) print(f[OK] 已连接设备 {ip}) if device.get(secret): conn.enable() if device[device_type] huawei: command display current-configuration else: command show running-config output conn.send_command(command, read_timeout30) with open(filename, w, encodingutf-8) as f: f.write(f# 设备: {ip}\n) f.write(f# 备份时间: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)}\n) f.write(# * 60 \n\n) f.write(output) print(f[OK] 设备 {ip} 配置已保存到 {filename}) conn.disconnect() write_log(f{ip} 备份成功 - {filename}) return True except Exception as e: print(f[ERROR] 设备 {ip} 备份失败: {e}) write_log(f{ip} 备份失败: {e}) return False def main(): print( * 50) print(交换机配置备份脚本) print(f开始时间: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)}) print(f待备份设备数: {len(devices)}) print( * 50) success_count 0 for device in devices: if backup_device(device): success_count 1 print( * 50) print(f备份完成成功 {success_count}/{len(devices)} 台) print(f备份文件位于: {os.path.abspath(BACKUP_DIR)}) print(f详细日志: {LOG_FILE}) print( * 50) if __name__ __main__: main()5.2 如何测试这个脚本第一次跑脚本我建议你先只放一台设备在devices列表里而且最好是那种你已经确认SSH能登录的设备。跑一遍之后打开backup_configs文件夹确认文件生成、内容完整再往列表里加其他设备。我自己的习惯是先小范围验证确认脚本正常再放量执行。你要是一上来就把一百台设备全塞进去万一有个设备把整个网络拖慢了你连排查都不知道从哪查起。如果有设备备份失败先看命令行窗口打印出来的错误信息。是密码不对IP不可达还是device_type填错了把单个设备的配置改正过来再重新跑一遍。脚本会自动保留之前成功备份的文件不会因为重跑而丢失。5.3 让脚本定时自动跑Windows计划任务的配置既然脚本写好了接下来就要考虑“懒人模式”——让它定时自动跑。Windows系统自带“任务计划程序”可以把脚本设置成每天凌晨固定时间运行。配置步骤很简单按Win R输入taskschd.msc回车打开任务计划程序。右侧点“创建基本任务”名称填“交换机配置每日备份”。触发器选择“每天”设置一个你下班后的时间比如晚上23:30。操作选“启动程序”程序或脚本填python参数填脚本的完整路径比如D:\scripts\backup_switch.py。完成。要注意的一点是如果脚本里用了相对路径比如backup_configs目录那么运行时的工作目录可能不是你脚本所在的目录。为了防止这个问题最稳妥的办法是在脚本开头加一行os.chdir(os.path.dirname(os.path.abspath(__file__)))意思就是“把当前工作目录切换到脚本自己所在的位置”这样不管从哪里启动脚本文件都会保存到正确的地方。5.4 定时任务跑不起来先手动跑一遍其实Windows计划任务最坑的地方在于你手动双击脚本能跑但计划任务就是跑不起来。这往往是因为计划任务启动Python时用的工作目录或者环境变量和你手动执行时不一样。排查方法很简单右键任务选择“运行”然后再看backup_configs目录有没有生成新的文件。如果没有去任务计划程序的“历史记录”标签页看有没有报错。大多数情况下报错原因都是Python路径没写对。建议在“程序或脚本”那一栏直接填Python的完整路径比如C:\Users\你的用户名\AppData\Local\Programs\Python\Python311\python.exe而不是简简单单填一个python。6. 常见问题与排查技巧实录6.1 连接失败的几个典型原因我把自己和身边朋友跑这个脚本过程中遇到的坑整理了一下做成一个速查表你遇到问题直接对着查就行。现象可能原因解决办法Connection timed out网络不通或设备防火墙拦截了SSH端口先手动ping设备IP确认设备SSH服务已开启Authentication failed用户名或密码错误手动SSH登录确认凭据注意密码是否有特殊字符需要转义ValueError: Unknown device_typedevice_type字段填错查netmiko支持的设备类型列表改成正确的连接后卡住不动设备SSH加密算法和paramiko不兼容升级paramiko库pip install --upgrade paramikoFailed to enter enable modeenable密码secret不正确确认特权模式密码不需要的话把secret字段删掉6.2 配置输出不完整或乱码怎么处理有时候备份出来的配置文件内容不完整或者中文注释全是乱码这通常是因为命令输出被分页符截断或者编码格式不对。Netmiko本身已经默认处理了分页符它会自动发空格或回车把输出刷完但有些老设备会有例外。遇到这种情况你可以在send_command之前先发一条命令关闭分页conn.send_command(screen-length 0 temporary) # 华为/H3C关闭分页 conn.send_command(terminal length 0) # 思科关闭分页关掉分页之后设备会一次性把配置全部输出不会出现“--More--”这种中间状态。至于乱码主要是编码问题。华为设备默认返回的是GBK编码的中文Python读取的时候如果按UTF-8解码就会乱码。我在脚本里统一用encodingutf-8写入文件如果你的设备输出有中文并且乱码可以把send_command的结果先做一次编码转换output conn.send_command(command, read_timeout30) # 如果是华为设备拿到GBK编码内容转成UTF-8字符串 output output.encode(gbk, errorsignore).decode(utf-8, errorsignore)不过这个处理方式因设备而异大部分场景下不需要额外处理遇到乱码再说。6.3 Python环境相关的报错pip和脚本执行常见问题网工群体很多不是程序员出身在Python环境上踩坑太正常了。我挑几个最常见的报错说一下报错1pip 无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称这基本就是pip所在的Scripts目录不在PATH里。解决方法前面说过把C:\Users\你的用户名\AppData\Local\Programs\Python\Python311\Scripts加进系统环境变量Path。报错2python 无法将“python”项识别为 cmdlet、函数、脚本文件或可运行程序的名称这表示Python本体没加入PATH或者安装的时候没勾选“Add Python to PATH”。最快的解决方法是卸载重装一遍安装时务必勾选那个选项。报错3因为在此系统上禁止运行脚本这个报错多出现在PowerShell环境下。微软默认的PowerShell执行策略是Restricted不允许直接运行.ps1或某些脚本。解决办法是Set-ExecutionPolicy -Scope CurrentUser RemoteSigned执行完后输入Y确认然后再跑脚本就正常了。报错4ModuleNotFoundError: No module named netmiko这个最简单就是netmiko没装或者装到了别的Python版本里。直接重新执行pip install netmiko然后确认你运行脚本用的Python和装库用的pip是同一个。6.4 我的独家建议先跑通一台再跑全部最后说一个我特别想强调的实操心得。很多朋友拿到脚本就急着把几百台设备信息全填进去结果跑起来一团糟这个失败那个超时最后心态崩了。我的建议是你一定要先跑通一台设备再扩展到三到五台确认稳定之后再放量。一台设备跑通只需要不到一分钟却能帮你排除掉80%的环境问题——Python环境问题、netmiko安装问题、设备SSH配置问题、脚本本身的问题这些都可以在单台设备测试时暴露出来。等这些坑全部踩平了再往列表里加设备你会发现后面的事情非常顺利。另外建议一次备份的间隔不要太短。我一般设置每天备份一次就够了如果网络变动频繁可以上午下午各一次。太频繁不仅浪费设备性能而且会产生大量冗余文件反而不好管理。7. 脚本之外的扩展思路备份只是自动化运维的第一步脚本跑通之后你的工作流会发生肉眼可见的变化——每天自动备份再也不用手动登录一台台设备。但这个脚本其实只是一个开始顺着这个思路往下延伸你能做的事情远比“备份配置”多得多。比如你可以在脚本基础上加上一个“配置对比”功能把昨天和今天的配置文件做diff有变化就推送消息提醒。这样任何设备配置被改动你当天就能知道不会等到出了问题才后知后觉。再比如你可以把备份文件直接提交到Git仓库利用Git的版本管理能力做配置历史追踪。每一次备份就是一个commit哪天的配置改了什么一目了然回滚也非常方便。还有如果你管理的是思科设备netmiko本身还支持下发配置send_config_set这意味着你可以用类似的方式做批量配置变更。今天你备份了配置明天你就能批量改VLAN、批量加接口描述效率提升一个量级。我在实际使用中最深的一个体会是网络工程师学Python不需要从零啃完一本编程书再动手。最好的学习方式就是带着一个具体的小需求比如今天这个“交换机配置备份”把脚本写出来、跑起来、踩几个坑你的Python水平会在解决问题的过程中飞速提升。等到你的脚本能稳定运作了那种实实在在的成就感真的比刷十遍教程都要强。所以别犹豫了。装好Python把这篇文章里的代码敲一遍把你手头几台设备的真实信息填进去跑起来看看。相信我当你看到备份文件整整齐齐出现在文件夹里的那一刻你会觉得用Python做网络自动化简直太爽了。