python封装paramiko上传下载轻松操作远程主机

1、简介

Paramiko是基于Python实现的SSH2远程安全连接,支持认证及密钥方式。可以实现远程命令执行、文件传输、中间SSH代理等功能,相对于Pexpect,封装的层次更高,更贴近SSH协议的功能。

Paramiko是基于Python(2.7,3.4+)版本实现和封装了SSHv2协议,底层是用cryptography实现,我们如果希望远程登录主机或者远程下载或者上传文件到远程主机都可以使用该库实现。Paramiko属于第三方python库,需要我们使用pip进行安装,如果是离线需要在有网络的环境下载好whl文件,再到对应的离线环境进行安装。

主要功能:

  • 类似于SSH协议,paramiko包含两个核心组件,一个为SSHClient类,另一个为SFTPClient类。
  • SSHClient类是SSH服务会话的高级表示,作用类似于Linux的ssh命令,是对SSH会话的封装。该类封装了传输(transport)、通道(channel)及SFTPClient的校验、建立的方法,通常用于执行远程命令。
  • SFTPClient作为一个SFTP客户端对象,作用类似与Linux的sftp命令,是对SFTP客户端的封装。根据SSH传输协议的sftp会话,实现远程文件操作,比如文件上传、下载、权限、状态等操作。
  • 概括来说,前者主要对远程主机进行操作,输入命令对远程主机进行控制,后者主要实现了从远程主机上上传下载文件,除此之外还有很多实用的方法,本文主要是自己在工作中经常使用的方法进行封装,更多更全面的介绍请参考paramiko的api文档https://www.paramiko.org/
  • Paramiko中的几个基础名词:

1、Channel:是一种类Socket,一种安全的SSH传输通道;
2、Transport:是一种加密的会话,使用时会同步创建了一个加密的Tunnels(通道),这个Tunnels叫做Channel;
3、Session:是client与Server保持连接的对象,用connect()/start_client()/start_server()开始会话。

总结:
ssh是一个协议,OpenSSH是其中一个开源实现,paramiko是Python的一个库,实现了SSHv2协议(底层使用cryptography)。有了Paramiko以后,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作。
由于paramiko属于第三方库,所以需要使用如下命令先行安装

pip install paramiko

2、paramiko封装代码

# coding=utf-8
from __future__ import print_function
import paramiko


class SSHConnection:
    def __init__(self, host='xxx.xxx.xxx.xxx', port=22, user='xxx', pwd='123456'):
        """初始化连接创建Transport通道"""
        self.host = host
        self.port = port
        self.user = user
        self.pwd = pwd
        self.__transport = paramiko.Transport((self.host, self.port))
        self.__transport.connect(username=self.user, password=self.pwd)
        self.sftp = paramiko.SFTPClient.from_transport(self.__transport)
        
    def __get_all_files_in_local_dir(self, local_dir):
       """获取windows指定目录及其子目录下的所有文件,未考虑目录结构"""
       # 保存所有文件的列表
       all_files = list()
       # 获取当前指定目录下的所有目录及文件,包含属性值
       files = os.listdir(local_dir)
       for x in files:
           # local_dir目录中每一个文件或目录的完整路径
           filename = os.path.join(local_dir, x)
           # 如果是目录,则递归处理该目录
           if os.path.isdir(x):
               all_files.extend(self.__get_all_files_in_local_dir(filename))
           else:
               all_files.append(filename)
       return all_files

    def __get_all_files_in_remote_dir(self, sftp, remote_dir):
        """获取远端linux主机上指定目录及其子目录下的所有文件,未考虑目录结构"""
        # 保存所有文件的列表
        all_files = list()
        # 去掉路径字符串最后的字符'/',如果有的话
        if remote_dir[-1] == '/':
            remote_dir = remote_dir[0:-1]
        # 获取当前指定目录下的所有目录及文件,包含属性值
        files = sftp.listdir_attr(remote_dir)
        for x in files:
            # remote_dir目录中每一个文件或目录的完整路径
            filename = remote_dir + '/' + x.filename
            # 如果是目录,则递归处理该目录,这里用到了stat库中的S_ISDIR方法,与linux中的宏的名字完全一致
            if S_ISDIR(x.st_mode):
                all_files.extend(self.__get_all_files_in_remote_dir(sftp, filename))
            else:
                all_files.append(filename)
        return all_files
        
    def upload(self, local_path, remote_path):
        """上传文件到远程主机"""
        try:
            self.sftp.put(local_path, remote_path)
        except:
            print('### put file {} failed!'.format(local_path))

    def download(self, local_path, remote_path):
        """从远程主机下载文件到本地"""
        try:
            self.sftp.get(remote_path, local_path)
        except:
            print('### get file {} failed!'.format(remote_path))

    def mkdir(self, target_path, mode=0o777):
        """在远程主机上创建目录"""
        try:
            self.sftp.stat(target_path)
        except:
            self.sftp.mkdir(target_path, mode)
            print("create dir: " + target_path)

    def make_dirs(self, dirs, mode=0o777):
        """在远程主机上创建多级目录"""
        num = len(dirs.split('/'))
        for i in reversed(range(num)):
            directory = dirs.rsplit('/', i)[0]
            if directory == '':
                directory = '/'
            try:
                self.sftp.stat(directory)
            except:
                self.sftp.mkdir(directory, mode)
                print("create dir: " + directory)

    def rmdir(self, target_path):
        """删除远程主机上的目录"""
        try:
            self.sftp.rmdir(target_path)
        except:
            pass

    def listdir(self, target_path):
        """查看目录下文件以及子目录(如果需要更加细粒度的文件信息建议使用listdir_attr)"""
        return self.sftp.listdir(target_path)

    def remove(self, target_path):
        """删除文件"""
        try:
            self.sftp.remove(target_path)
        except:
            pass

    def listdirattr(self, target_path):
        """查看目录下文件以及子目录的详细信息(包含内容和参考os.stat返回一个FSTPAttributes对象,对象的具体属性请用__dict__查看)"""
        try:
            list_dir = self.sftp.listdir_attr(target_path)
        except BaseException as e:
            print(e)
            return
        return list_dir

    def rename(self, oldpath, newpath):
        """重命名文件"""
        self.sftp.rename(oldpath, newpath)

    def stat(self, remote_path):
        """获取文件(directory or file)详情"""
        return self.sftp.stat(remote_path)

    def close(self):
        """关闭通道"""
        self.sftp.close()
        self.__transport.close()

    def cmd(self, command):
        """SSHClient输入命令远程操作主机"""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
        ssh._transport = self.__transport
        stdin, stdout, stderr = ssh.exec_command(command)
        result = stdout.read()
        print(result)
        return result 

3、python封装paramiko实例演示

  • 实例化
    ip = '192.168.100.12'
    port = 22
    user = 'root'
    pwd = '123456'

    ssh = SSHConnection(ip, port, user, pwd)
  • 上传文件到远程主机(可以重命名),注意两个目录都要精确到文件名
 ssh.upload(r'./test.py', r'/home/test/test_1.py') 
  • 从远程主机下载文件到本地(可以重命名到本地),注意两个目录都要精确到文件名
ssh.download('./test.sh', '/home/test/test111.sh') 
  • 在远程主机上创建文件夹
ssh.mkdir('/home/test/1') 
  • 在远程主机上创建目录
ssh.make_dirs('/home/test/111/222/333')
  • 删除目录
ssh.rmdir('/home/test/111/222/333')
  • 查看目录下文件以及子目录
list_dir = ssh.listdir('/home/test/')
  • 删除文件
ssh.remove('/home/test/test2025.txt')
  • 查看目录下文件以及子目录的详细信息
list_files = ssh.listdirattr('/home/test/')
print('list_files=', list_files)
print(list_files[0].__dict__)
  • 重命名文件/移动文件; 若路径不同,则会移动文件。
ssh.rename('/home/test/test1.txt', '/home/test/test2025.txt')

-获取文件详情

file_stat = ssh.stat('/home/test/test1.py')
print(file_stat)
ssh.cmd('pwd && cd /home/test && touch test1.txt')
  • 关闭通道
ssh.close()

参考文献:
https://www.cnblogs.com/xiao-apple36/p/9144092.html
https://www.cnblogs.com/linux985/p/11112538.html
https://www.cnblogs.com/haigege/p/5517422.html

4、附录

nohup重定向日志输出

shell常用操作–一次性执行多条命令

参考:
https://www.cnblogs.com/python-nameless/p/6855804.html


加星
点关注
谢谢
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值