根据工作需求,需要向多个服务器传输多个相同的文件或文件夹,paramiko自带的 put 功能只能传输单个文件,此文中记录一下批量传输文件或文件夹的脚本,以及会根据文件大小判定文件是否传输成功。
需要用到的模块:
import xlrd
import paramiko
import os
import time
import re
1. 使用 paramiko 和 transport 创建 ssh 和 sftp 连接
transport = paramiko.Transport((ip, 22))
transport.connect(username=username, password=password)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 自动添加策略,保存服务器的主机名和秘钥信息,不添加,不在本地hnow_hosts文件中的记录将无法连接
ssh._transport = transport
sftp = paramiko.SFTPClient.from_transport(transport)
2. 文件拷贝
整个脚本的关键之处,定义传输函数,传参有ssh、sftp、本地地址、上传地址,分别判断本地地址与远程传输地址。判断本地地址是否是目录,如果是目录则一直递归,如果是文件,则删除老文件,上传新的文件。
def _copy(ssh, sftp, local, remote):
# 判断remote是否是目录
if _is_exists(remote, function=sftp.chdir):
# 是,获取local路径中的最后一个文件名拼接到remote中
filename = os.path.basename(os.path.normpath(local))
remote = os.path.join(remote, filename).replace('\\', '/')
# 如果local为目录
if os.path.isdir(local):
# 在远程创建相应的目录
_is_exists(remote, function=sftp.mkdir)
# 遍历local
for file in os.listdir(local):
# 取得file的全路径
localfile = os.path.join(local, file).replace('\\', '/')
# 深度递归_copy()
_copy(ssh=ssh, sftp=sftp, local=localfile, remote=remote)
# 如果local为文件
if os.path.isfile(local):
try:
ssh.exec_command("rm -rf %s"%(remote))
time.sleep(1)
sftp.put(local, remote)
except Exception as error:
print(error)
print('[put]', local, '==>', remote, 'FAILED')
else:
print('[put]', local, '==>', remote, 'SUCCESSED')
3. 判断地址是否存在
处理地址格式,并判断该目录是否存在。
def _is_exists(path, function):
path = path.replace('\\', '/')
try:
function(path)
except Exception as error:
return False
else:
return True
整个脚本代码:
import xlrd
import paramiko
import os
import time
import re
CSheet = xlrd.open_workbook(r'C:\Users\Administrator\Desktop\11.xlsx')
data = CSheet.sheets()[0]
nrow = data.nrows
FailedList = []
# 检查路径是否存在
def _is_exists(path, function):
path = path.replace('\\', '/')
try:
function(path)
except Exception as error:
return False
else:
return True
# 拷贝文件
def _copy(ssh, sftp, local, remote):
# 判断remote是否是目录
if _is_exists(remote, function=sftp.chdir):
# 是,获取local路径中的最后一个文件名拼接到remote中
filename = os.path.basename(os.path.normpath(local))
remote = os.path.join(remote, filename).replace('\\', '/')
# 如果local为目录
if os.path.isdir(local):
# 在远程创建相应的目录
_is_exists(remote, function=sftp.mkdir)
# 遍历local
for file in os.listdir(local):
# 取得file的全路径
localfile = os.path.join(local, file).replace('\\', '/')
# 深度递归_copy()
_copy(ssh=ssh, sftp=sftp, local=localfile, remote=remote)
# 如果local为文件
if os.path.isfile(local):
try:
ssh.exec_command("rm -rf %s"%(remote))
time.sleep(1)
sftp.put(local, remote)
except Exception as error:
print(error)
print('[put]', local, '==>', remote, 'FAILED')
else:
print('[put]', local, '==>', remote, 'SUCCESSED')
for i in range(1, nrow):
ip = data.row_values(i)[0]
try:
transport = paramiko.Transport((ip, 22))
transport.connect(username=username, password=password)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 自动添加策略,保存服务器的主机名和秘钥信息,不添加,不在本地hnow_hosts文件中的记录将无法连接
ssh._transport = transport
print("%s 连接成功" % (ip))
sftp = paramiko.SFTPClient.from_transport(transport)
_copy(ssh=ssh, sftp=sftp, local='C:\\Users\\Administrator\\Desktop\\test', remote='/etc/test')
except Exception as reason:
print(reason)
FailedList.append(ip)
print("连接失败列表:")
for j in FailedList:
print(j)
结束。