首页 > 编程语言 > 详细

paramiko的常规使用示例-python

时间:2020-11-15 18:22:39      阅读:31      评论:0      收藏:0      [点我收藏+]

  本示例全程使用函数式编程思想,面对对象的编程思想从未体现。

  若有不足之处,还望斧正,谢谢各位前辈、大佬、同行者。

import paramiko
import re
import time
import os
‘‘‘
本端均指Windows
远端均指常规Linux发行版
写入文件的错误记录:
将会使用errInfoFileList和outInfoFileList字典中指定为文件名称写入,每次运行时,每个主机的错误信息均会记录到errInfoFileList[host]指定的文件中。
‘‘‘

#passwords = {‘2409:8069:5A06:1405::127:2021‘:‘Cmcc_2o20‘,‘2409:8069:5A06:1405::127:2022‘:‘Cmcc_2o20‘,‘2409:8069:5A06:1405::127:2031‘:‘Admin_123‘,‘2409:8069:5A06:1405::127:2032‘:‘Admin_123‘}
#hosts = [‘2409:8069:5A06:1405::127:2021‘,‘2409:8069:5A06:1405::127:2022‘,‘2409:8069:5A06:1405::127:2031‘,‘2409:8069:5A06:1405::127:2032‘]
#users = {‘2409:8069:5A06:1405::127:2021‘:‘admin‘,‘2409:8069:5A06:1405::127:2022‘:‘admin‘,‘2409:8069:5A06:1405::127:2031‘:‘admin‘,‘2409:8069:5A06:1405::127:2032‘:‘admin‘}
#passwords = {‘s3.nsloop.com‘:‘Lovedan‘}
#hosts = [‘s3.nsloop.com‘]
#users = {‘s3.nsloop.com‘:"admin"}
#hosts=[‘2409:8080:5a0a:750c::8241‘]
#passwords = {‘2409:8080:5a0a:750c::8241‘:‘Lovedan‘}
#users = {‘2409:8080:5a0a:750c::8241‘:"admin"}
hosts=[192.168.50.25]
passwords = {192.168.50.25:Lovedan}
users = {192.168.50.25:"Administrator"}

errInfoFileList={}      #用于在同一次运行中保持文件名相同
outInfoFileList={}      #用于在同一次运行中保持文件名相同

def my_exec_command(SSHClient__,commandString,getPty=False):
    ‘‘‘
    进行了一次错误捕捉,仍然返回三个经典参数
    get_pty:是否保持终端
    ‘‘‘
    try:
        stdin, stdout, stderr = SSHClient__.exec_command(commandString,get_pty = getPty)
    except Exception as errMsg:
        print("虽然exec_command报错了,但是不需要管他.")
        print("这是报错信息:")
        print("{}:\t{}".format(Exception,errMsg))
    return stdin, stdout, stderr

def isError(stdErr):
    ‘‘‘
    检查命令的输出有没有错误信息,有返回True,和错误信息(string 类型),没有返回False和None
    请传入stderr,而不是stdin或者stdout
    ‘‘‘
    errStr = stdErr.read().decode()
    if len(errStr) == 0:
        return False,None
    else:
        return True,errStr

def errInfoToFile(host,errinfo,commandString):
    ‘‘‘
    用于将命令执行过程中的错误信息保存下来
    ‘‘‘
    if host not in errInfoFileList:
        currentTime = time.localtime()
        fileTime=str(currentTime.tm_year) + "" + str(currentTime.tm_mon) + "" + str(currentTime.tm_mday) + "" + str(currentTime.tm_hour) + "" + str(currentTime.tm_min) + ""
        fileName = re.sub(r:|\.,-,host) + _commandErrorLog_{}.txt.format(fileTime)
        errInfoFileList[host] = fileName
        with open(fileName,a,encoding= UTF8,newline=‘‘) as errFile:
            print("命令:{} 的错误信息".format(commandString),file=errFile)
            print(errinfo,file=errFile,end=‘‘)
            print(‘‘,file=errFile)
    else:
        fileName = errInfoFileList[host]
        errInfoFileList[host] = fileName
        with open(fileName,a,encoding= UTF8,newline=‘‘) as errFile:
            print("命令:{} 的错误信息:".format(commandString),file=errFile)
            print(errinfo,file=errFile,end=‘‘)
            print(‘‘,file=errFile)

def outInfoToFile(host,outinfo,commandString):
    ‘‘‘
    用于将命令执行过程中的输出信息保存下来
    ‘‘‘
    if host not in outInfoFileList:
        currentTime = time.localtime()
        fileTime=str(currentTime.tm_year) + "" + str(currentTime.tm_mon) + "" + str(currentTime.tm_mday) + "" + str(currentTime.tm_hour) + "" + str(currentTime.tm_min) + ""
        fileName = re.sub(r:|\.,-,host) + _commandOutLog_{}.txt.format(fileTime)
        outInfoFileList[host] = fileName
        with open(fileName,a,encoding= UTF8,newline=‘‘) as outFile:
            print("命令:{} 的输出信息:".format(commandString),file=outFile)
            print(outinfo,file=outFile,end=‘‘)
            print(‘‘,file=outFile)
    else:
        fileName = outInfoFileList[host]
        outInfoFileList[host] = fileName
        with open(fileName,a,encoding= UTF8,newline=‘‘) as outFile:
            print("命令:{} 的输出信息:".format(commandString),file=outFile)
            print(outinfo,file=outFile,end=‘‘)
            print(‘‘,file=outFile)

def checkAndEstablishRemotePath(sftpclient,host,path=None):
    #检查远程主机上目标目录是否存在,存在返回True
    #不存在则建立,建立失败返回None,并输出错误原因到文件中,建立成功返回True
    #此函数只适用于Linux,测试的发行版为CentOS 6-7
    #且需要创建的路径为绝对路径而不是相对路径
    if path == None:
        errInfoToFile(sftpclient.host,"path:{} 不存在。".format(path),cd None)
        return None
    try:
        sftpclient.listdir(path)
    except Exception as errMsg:
        #print(‘{}:{}‘.format(Exception,errMsg))
        try:
            sftpclient.mkdir(path)
        except Exception as errMsg:
            errInfoToFile(host,{}:{}.format(Exception,errMsg),sftpclient.mkdir({}).format(path))
            print({}:{}.format(Exception,errMsg))
            return None
        return True
    else:
        return True

def checkAndEstablishLocalPath_win(path=None):
    #检查path指定的路径本地是否存在,若不存在,创建它
    #若存在,返回True
    #若创建成功,返回True,若创建失败,打印原因,然后返回None
    #此函数仅适用于Windows主机
    if path == None:
        return None
    if os.path.exists(path):
        return True
    else:
        #创建
        try:
            os.mkdir(path)
        except Exception as errMsg:
            errInfoToFile(localhost,{}:{}.format(Exception,errMsg),os.mkdir({}).format(path))
            print({}:{}.format(Exception,errMsg))
            return None
        return True

def CheckRemoteHostFilePathExists(sftpclient,filePath=None):
    ‘‘‘
    检查远程主机上是否存在需要下载的文件,存在返回True,不存在返回None
    ‘‘‘
    if filePath == None:
        errInfoToFile(sftpclient.host,"path:{} 不存在。".format(filePath),cd None)
        return None
    else:
        try:
            sftpclient.stat(filePath)
        except Exception as errMsg:
            errInfoToFile(localhost,{}:{}.format(Exception,errMsg),sftpclient.stat({}).format(filePath))
            print({}:{}.format(Exception,errMsg))
            return None
        return True

def main_():
    #普通命令
    commandList = [pwd,whoami]
    ssh = paramiko.SSHClient()
    for host in hosts:
        #若主机之前未连接过,自动选择yes添加到本地know_hosts文件
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(host,username=users[host],password=passwords[host],timeout=10)
        for command in commandList:
            stdin, stdout, stderr = my_exec_command(ssh,command)
            chcekErrRet =  isError(stderr)
            if chcekErrRet[0]:
                errInfoToFile(host,chcekErrRet[1],command)
                print(chcekErrRet[1])
                #是否要停止继续执行命令
            outInfo = stdout.read().decode()
            outInfoToFile(host,outInfo,command)
            print(outInfo)
    ssh.close()
def main_sudo():
    #sudo 命令
    commandList = [ls -al /home/administrator,cat /etc/shadow]
    ssh = paramiko.SSHClient()
    for host in hosts:
        #若主机之前未连接过,自动选择yes添加到本地know_hosts文件
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh.connect(host,port=32215,username=users[host],password=passwords[host],timeout=10)
        except Exception as errMsg:
            print("({}:{}".format(Exception,errMsg))
            errInfoToFile(host,"({}:{}".format(Exception,errMsg),"ssh@{}".format(host)) #最好加上端口信息
            continue
        for command in commandList:
            #构建sudo命令:
            command = echo {} | .format(passwords[host]) + command
            print(command)
            stdin, stdout, stderr = my_exec_command(ssh,command,True)
            chcekErrRet =  isError(stderr)
            if chcekErrRet[0]:
                errInfoToFile(host,chcekErrRet[1],command)
                print(chcekErrRet[1])
                continue
            outInfo = stdout.read().decode()
            if len(re.findall(r\[sudo\]\s{}.format(users[host]),outInfo,re.IGNORECASE)) != 0:
                #输入密码
                time.sleep(3) # 与终端交互,输入密码 注意:要是与终端交互最好sleep一下,否则会出现卡住的现象
                stdin.write(passwords[host]+\n)
                stdin.flush()
            outInfo += stdout.read().decode()
            outInfoToFile(host,outInfo,command)
            print(outInfo)
    ssh.close()
def main_get_put():
    ‘‘‘
    上传单个文件
    下载单个文件
    ‘‘‘
    putFileFullPathList = [rF:\temp\old-2020年11月6日\odbsci.xml]
    putFileToRemotePathList = [r/home/admin/]
    getFileLocalPathList = [rF:\temp\old-2020年11月6日]
    getFileRemotePathList = [r/home/admin/df.txt]
    port = 22
    for host in hosts:
        transport = paramiko.Transport((host,port))
        try:
            transport.connect(username=users[host],password=passwords[host])
            sftpClient = paramiko.SFTPClient.from_transport(transport)
        except Exception as errMsg:
            print({}:{}.format(Exception,errMsg))
            errInfoToFile(host,{}:{}.format(Exception,errMsg),sftp连接{}.format(host))
            continue
        #上传文件
        #若有重名文件,执行覆盖操作,请上传之前注意这一点。
        #也可以写一个检查远程主机的目标目录中是否存在这个文件。然后做提示
        for putFile in putFileFullPathList:
            if os.path.exists(putFile):         #检查本地文件是否存在
                for putFileToRemotePath in putFileToRemotePathList:
                    if checkAndEstablishRemotePath(sftpClient,host,putFileToRemotePath):
                        #远程目录必须指定文件名,这里使用的是本地文件名称,若是需要重命名,可以通过传参等方式重构本处。
                        fileName = re.findall(r(?<=\\)[^\\]+$,putFile,re.IGNORECASE)
                        if len(fileName) != 0:
                            fileName = fileName[0]
                            try:
                                sftpClient.put(putFile,putFileToRemotePath + fileName)
                            except Exception as errMsg:
                                print({}:{}.format(Exception,errMsg))
                                errInfoToFile(host,{}:{}.format(Exception,errMsg),sftp上传文件:{} 到远程目录:{}.format(putFile,putFileToRemotePath))
                            else:
                                print(成功上传 {} 到 {}.format(fileName,putFileToRemotePath))
                        else:
                            print("未匹配到文件名,不可上传。")
                            errInfoToFile(host,"未匹配到文件名,不可上传。",sftp上传文件:{} 到远程目录:{}.format(putFile,putFileToRemotePath))
        
        #下载文件
        #也是默认执行
        #这里不进行提示文件已存在,是否覆盖。
        for lcoalPath in getFileLocalPathList:
            if checkAndEstablishLocalPath_win(lcoalPath):
                for remoteFilePath in getFileRemotePathList:
                    if CheckRemoteHostFilePathExists(sftpClient,remoteFilePath):
                        fileName = re.findall(r(?<=/)[^/]+$,remoteFilePath,re.I)
                        if len(fileName) != 0:
                            fileName = fileName[0]
                        else:
                            print("远程文件路径:{} 未能匹配到文件名。".format(remoteFilePath))
                            errInfoToFile(host,"远程文件路径:{} 未能匹配到文件名。".format(remoteFilePath),r"re.findall(r‘(?<=/)[^/]+$‘,{},re.I)".format(remoteFilePath))
                            continue
                        try:
                            sftpClient.get(remoteFilePath,"{}\\{}".format(lcoalPath,fileName))
                        except Exception as errMsg:
                            print({}:{}.format(Exception,errMsg))
                            errInfoToFile(host,{}:{}.format(Exception,errMsg),sftp下载文件 {} 到本地目录 {} .format(remoteFilePath,lcoalPath))
                            continue
        sftpClient.close()

def RemotePathStructure(LocalPath,RemotePath):
    #通过本地目录,来构造远程主机上的文件路径
    #本地主机指Windows
    #远程主机指Linux(常规发行版)
    #返回构造完成的远程文件目录列表以及本地路径列表,返回值中,第一个值是远端文件列表,第二个是本地路径列表
    #LocalPath是string类型,且不以斜杠结尾
    #RemotePath是string类型,且不以反斜杠结尾
    if len(LocalPath) == 0 or len(RemotePath) == 0:
        print(本地路径或者远程路径的长度不能为0)
        errInfoToFile(localhost,"本地路径或者远程路径的长度不能为0","len(LocalPath) == 0 or len(RemotePath) == 0")
        return []
    if LocalPath[-1] == \\:
        LocalPath = LocalPath[0:len(LocalPath)-1]
    if RemotePath[-1] == /:
        RemotePath = RemotePath[0:len(LocalPath)-1]

    RemotePathList =[]
    lcoalpathList = []
    if os.path.exists(LocalPath):
        FilePethList = os.listdir(LocalPath)
        for fileName in FilePethList:
            filePath = "{}\\{}".format(LocalPath,fileName)
            if os.path.isdir(filePath):     #若不需要追踪链接,应该先使用os.path.islink来判断
                RmPath = "{}/{}".format(RemotePath,fileName)
                RPL,LPL = RemotePathStructure(filePath,RmPath)
                RemotePathList.extend(RPL)
                lcoalpathList.extend(LPL)
                continue
            else:
                RmPath = "{}/{}".format(RemotePath,fileName)
                RemotePathList.append(RmPath)
            lcoalpathList.append(filePath)
    else:
        print(本地路径不存在)
        errInfoToFile(localhost,"本地路径不存在","os.path.exists(p{})".format(LocalPath))
        return []
    return RemotePathList,lcoalpathList

def lcoalPathStructure(host,port,username,password,remotePath,localpath):
    #使用ssh方式从远程主机上获取目录,文件信息,然后构造需要下载的远程文件的绝对路径和本地存放的绝对路径
    #参数均为string类型。
    #LocalPath是string类型,且不以斜杠结尾
    #RemotePath是string类型,且不以反斜杠结尾
    #返回构造完成的远程文件路径列表和本地文件路径列表
    #有许多情况都会导致返回空列表,比如传参类型不对,长度为0,连接远程失败,登录的用户无法执行命令
    #返回值中,第一个是本地路径列表,第二个是远端路径列表
    #所涉及到的命令:ls -l 、cd 
    ‘‘‘
    if not (repr(type(remotePath)) != repr(type(‘‘)) or repr(type(localpath)) != repr(type(‘‘))):
        print(‘参数:remotePath或者localpath的类型不为string。type(remotePath):{}\ttype(localpath):{}‘.format(type(remotePath),type(localpath)))
        errInfoToFile(host,‘参数:remotePath或者localpath的类型不为string。type(remotePath):{}\ttype(localpath):{}‘.format(type(remotePath),type(localpath)),"if not (repr(type(remotePath)) != repr(type(‘‘)) or repr(type(localpath)) != repr(type(‘‘))):")
        return [],[]
    ‘‘‘
    if not(len(remotePath) != 0 or len(localpath) != 0):
        print(参数:remotePath或者localpath的长度为0。len(remotePath):{}\tlen(localpath):{}.format(len(remotePath),len(localpath)))
        errInfoToFile(host,参数:remotePath或者localpath的长度为0。len(remotePath):{}\tlen(localpath):{}.format(len(remotePath),len(localpath)),"if not(len(remotePath) != 0 or len(localpath) != 0):")
        return [],[]
    ssh = paramiko.SSHClient()
    #若主机之前未连接过,自动选择yes添加到本地know_hosts文件
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        ssh.connect(host,username=users[host],password=passwords[host],timeout=10)
    except Exception as errMsg:
        print({}:{}.format(Exception,errMsg))
        errInfoToFile(host,{}:{}.format(Exception,errMsg),ssh连接{}.format(host))
        return [],[]
    command = ls -l {}.format(remotePath)
    try:
        stdin, stdout, stderr = my_exec_command(ssh,command)
    except Exception as errMsg:
        print({}:{}.format(Exception,errMsg))
        errInfoToFile(host,{}:{}.format(Exception,errMsg),command)
        return [],[]
    chcekErrRet =  isError(stderr)
    if chcekErrRet[0]:
        errInfoToFile(host,chcekErrRet[1],command)
        print(chcekErrRet[1])
    ls_l_command_out = stdout.read().decode()
    outLineList = re.findall(r.+,ls_l_command_out,re.I)
    #print(outLineList)
    retRemotePathList=[]
    retlocalPathList=[]
    outLineList = outLineList[1:len(outLineList)]      #忽略第一行数据
    if len(outLineList) != 0:
        for outLine in outLineList:
            mode = re.findall(r^[a-z-]{10},outLine,re.I)
            if len(mode) != 0:
                mode= mode[0]
                #print("mode[0]:{}".format(mode[0]))
                if mode[0] == d or mode[0] == D:
                    #目录
                    fileName =‘‘
                    fileName_1 = re.findall(r(?<=\d\s\d\d:\d\d ).+,outLine,re.I)
                    fileName_2 = re.findall(r(?<=\d\s\d\d\d\d ).+,outLine,re.I)
                    if len(fileName_1) != 0 and len(fileName_2) != 0:
                        input("快来看,真的有同时符合两种模式的文件哎:\n{}".format(outLine))
                    if len(fileName_1) == 0 and len(fileName_2) == 0:
                        input("没有匹配到目录名,检查一下,outLine:\n{}\nfileName_1:{}\tfileName_2:{}".format(outLine,fileName_1,fileName_2))
                    if len(fileName_1) != 0:
                        fileName = fileName_1[0]
                    if len(fileName_2) != 0:
                        fileName = fileName_2[0]
                    #递归
                    remotePath_ = "{}/{}".format(remotePath,fileName)
                    localpath_ = "{}\\{}".format(localpath,fileName)
                    LPL,RPL = lcoalPathStructure(host,port,username,password,remotePath_,localpath_)
                    #列表类型
                    retlocalPathList.extend(LPL)
                    retRemotePathList.extend(RPL)
                elif mode[0] == l or mode[0] == L:
                    #链接
                    fileName =‘‘
                    fileName_1 = re.findall(r(?<=\d\s\d\d:\d\d ).+?(?= ->),outLine,re.I)
                    fileName_2 = re.findall(r(?<=\d\s\d\d\d\d ).+?(?= ->),outLine,re.I)
                    if len(fileName_1) != 0 and len(fileName_2) != 0:
                        input("快来看,真的有同时符合两种模式的文件哎:\n{}".format(outLine))
                    if len(fileName_1) == 0 and len(fileName_2) == 0:
                        input("没有匹配到链接名,检查一下,outLine:\n{}\nfileName_1:{}\tfileName_2:{}".format(outLine,fileName_1,fileName_2))
                    if len(fileName_1) != 0:
                        fileName = fileName_1[0]
                    if len(fileName_2) != 0:
                        fileName = fileName_2[0]
                    linkPath = re.findall(r(?<= ->\s).+,outLine,re.I)
                    if(linkPath) != 0:
                        linkPath = linkPath[0]
                    else:
                        input("没有匹配到链接所指向的内容,检查一下:\n{}".format(outLine))
                    #检查是否是目录
                    command = "cd {}/{}".format(remotePath,fileName)
                    try:
                        stdin, stdout, stderr = my_exec_command(ssh,command)
                    except Exception as errMsg:
                        print({}:{}.format(Exception,errMsg))
                        errInfoToFile(host,{}:{}.format(Exception,errMsg),command)
                        continue
                    chcekErrRet =  isError(stderr)
                    if chcekErrRet[0]:
                        #说明不是目录
                        if linkPath[0] != /:
                            RPL = "{}/{}".format(remotePath,linkPath)
                        else:
                            RPL = linkPath
                        LPL = "{}\\{}".format(localpath,fileName)
                        #字符串类型
                        retlocalPathList.append(LPL)
                        retRemotePathList.append(RPL)
                    else:
                        #是目录,递归
                        if linkPath[0] != /:
                            remotePath_ = "{}/{}".format(remotePath,linkPath)
                        else:
                            remotePath_ = linkPath
                        localpath_ = "{}\\{}".format(localpath,fileName)
                        LPL,RPL = lcoalPathStructure(host,port,username,password,remotePath_,localpath_)
                        #列表类型
                        retlocalPathList.extend(LPL)
                        retRemotePathList.extend(RPL)
                else:
                    #其他文件
                    fileName =‘‘
                    fileName_1 = re.findall(r(?<=\d\s\d\d:\d\d ).+,outLine,re.I)
                    fileName_2 = re.findall(r(?<=\d\s\d\d\d\d ).+,outLine,re.I)
                    if len(fileName_1) != 0 and len(fileName_2) != 0:
                        input("快来看,真的有同时符合两种模式的文件哎:\n{}".format(outLine))
                    if len(fileName_1) == 0 and len(fileName_2) == 0:
                        input("没有匹配到文件名,检查一下,outLine:\n{}\nfileName_1:{}\tfileName_2:{}".format(outLine,fileName_1,fileName_2))
                    if len(fileName_1) != 0:
                        fileName = fileName_1[0]
                    if len(fileName_2) != 0:
                        fileName = fileName_2[0]
                    RPL = "{}/{}".format(remotePath,fileName)
                    LPL = "{}\\{}".format(localpath,fileName)
                    #字符串类型
                    retlocalPathList.append(LPL)
                    retRemotePathList.append(RPL)
            else:
                input("请确认,匹配文件属性值未匹配到:{}".format(outLine))
    else:
        #对于空目录
        retRemotePathList.append(remotePath)
        filename = re.findall(r(?<=/)[^/]+$,remotePath,re.I)
        if len(filename) == 0:
            return [],[]
        else:
            filename = filename[0]
        retlocalpath = "{}\\{}".format(localpath,filename)
        retlocalPathList.append(retlocalpath)
    #print("retlocalPathList:{}\nretRemotePathList:{}".format(retlocalPathList,retRemotePathList))
    return retlocalPathList,retRemotePathList

def main():
    #上传整个目录
    #下载整个目录
    #若目录中含有目录链接,会追踪该链接。
    ‘‘‘
    putLocalPathList = [r‘D:\Music‘]               #上传的本地目录
    putRemotePathList = [‘/home/admin/Music‘]      #上传到远程主机的路径
    localFilePathList = []                         #存储本地待上传或下载的文件路径
    remoteFilePathList = []                        #存储远程待上传或下载的文件路径
    port = 22
    #上传
    
    for localpath in putLocalPathList:
        for remotePath in putRemotePathList:
            remoteFilePathList,localFilePathList = RemotePathStructure(localpath,remotePath)
            if len(remoteFilePathList) == len(localFilePathList):
                for host in hosts:
                    transport = paramiko.Transport((host,port))
                    try:
                        transport.connect(username=users[host],password=passwords[host])
                        sftpClient = paramiko.SFTPClient.from_transport(transport)
                    except Exception as errMsg:
                        print(‘{}:{}‘.format(Exception,errMsg))
                        errInfoToFile(host,‘{}:{}‘.format(Exception,errMsg),‘sftp连接{}‘.format(host))
                        continue
                    for index in range(len(remoteFilePathList)):
                        #print(remoteFilePathList[index])
                        remotePath = re.findall(r".*/",remoteFilePathList[index],re.I)
                        if len(remotePath) == 0:
                            print("未从远程文件路径列表中的元素中匹配到远程路径:{}".format(remoteFilePathList[index]))
                            errInfoToFile(host,"未从远程文件路径列表中的元素中匹配到远程路径","re.findall(r‘.*/‘,{},re.I)".format(remoteFilePathList[index]))
                            continue
                        else:
                            remotePath = remotePath[0]
                        if checkAndEstablishRemotePath(sftpClient,host,remotePath):
                            #远程目录必须指定文件名,这里使用的是本地文件名称,若是需要重命名,可以通过传参等方式重构本处。
                            try:
                                sftpClient.put(localFilePathList[index],remoteFilePathList[index])
                            except Exception as errMsg:
                                print(‘{}:{}‘.format(Exception,errMsg))
                                errInfoToFile(host,‘{}:{}‘.format(Exception,errMsg),‘sftp上传文件:{} 到远程目录:{}‘.format(localFilePathList[index],remoteFilePathList[index]))
                            else:
                                print(‘成功上传 {} 到 {}‘.format(localFilePathList[index],remoteFilePathList[index]))
                        else:
                            print("远程目录未创建成功")
            else:
                print("构造出来的本地文件列表和远程文件列表数量不一致")
    ‘‘‘
    getLocalPathList = [rC:\Users\Administrator\Desktop\temp\2020年11月11日\test]                   #上传的本地目录
    getRemotePathList = [/etc]                                                                     #上传到远程主机的路径 
    localFilePathList = []                                                                           #存储本地待上传或下载的文件路径
    remoteFilePathList = []                                                                          #存储远程待上传或下载的文件路径
    port = 22                                                                                        #也许可以设置一个全局端口字典
    #下载
    for localpath in getLocalPathList:
        for remotePath in getRemotePathList:
            for host in hosts:
                localFilePathList,remoteFilePathList = lcoalPathStructure(host,port,users[host],passwords[host],remotePath,localpath)
                if (len(remoteFilePathList) == len(localFilePathList)) and (remoteFilePathList != [] and localFilePathList != []):
                    print("记录并构造了{}个文件路径。".format(len(localFilePathList)))
                    transport = paramiko.Transport((host,port))
                    try:
                        transport.connect(username=users[host],password=passwords[host])
                        sftpClient = paramiko.SFTPClient.from_transport(transport)
                    except Exception as errMsg:
                        print({}:{}.format(Exception,errMsg))
                        errInfoToFile(host,{}:{}.format(Exception,errMsg),sftp连接{}.format(host))
                        continue
                    successfulNumber = 0                        #记录下载成功的数量
                    failedNumber = 0                            #记录下载失败的数量,失败的记录会输出到脚本同目录下的日志文件中
                    for index in range(len(remoteFilePathList)):
                        localPath = re.findall(r".+\\",localFilePathList[index],re.I)
                        if len(localPath) == 0:
                            print("未从本地文件路径列表中的元素中匹配到本地路径:{}".format(localFilePathList[index]))
                            errInfoToFile(host,"未从远程文件路径列表中的元素中匹配到本地路径","re.findall(r‘.+\\‘,{},re.I)".format(localFilePathList[index]))
                            continue
                        else:
                            localPath = localPath[0]
                            if not os.path.exists(localPath):
                                try:
                                    #创建本地目录
                                    os.makedirs(localPath)
                                except Exception as errMsg:
                                    print({}:{}.format(Exception,errMsg))
                                    errInfoToFile(host,{}:{}.format(Exception,errMsg),"创建本地目录:{}".format(localPath))
                                    failedNumber += 1
                                    continue
                            #若需要重命名,请增加逻辑
                            try:
                                sftpClient.get(remoteFilePathList[index],localFilePathList[index])
                            except Exception as errMsg:
                                print({}:{}.format(Exception,errMsg))
                                errInfoToFile(host,{}:{}.format(Exception,errMsg),sftp下载文件:{} 到本地目录:{}.format(remoteFilePathList[index],localFilePathList[index]))
                                failedNumber += 1
                            else:
                                print(成功下载文件 {} 到 {}.format(remoteFilePathList[index],localFilePathList[index]))
                                successfulNumber += 1
                        #print(localFilePathList[index])
                        print("记录的文件里边数目:{}\n下载成功的文件的数量:{}\n下载失败的文件数量:{}".format(len(localFilePathList),successfulNumber,failedNumber))
                else:
                    print("构造出来的本地文件列表和远程文件列表数量不一致;或者均为空列表。")

main()

后续可能会更新多线程或者多进程的版本。

paramiko的常规使用示例-python

原文:https://www.cnblogs.com/love-DanDan/p/13977090.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!