python3使用paramiko实现远程文件的上传下载

1、简述paramiko

py2和py3都可以使用这个模块。它是通过SSH2协议(底层使用cryptography)??来与远程服务器建立安全(加密和认证)连接的。与SSL(aka TLS)不同的是,SSH2协议不需要由强大的中央机构签署的分层证书。另外需要知道的是,为了安全访问远程shell,才使用SSH2协议替换Telnet和rsh,而且SSH2协议还具有通过加密隧道向远程服务打开任意通道的能力(例如,这是SFTP的工作方式)。(抱歉,英语不太过关,这个翻译的有些生硬)
通过使用Paramiko,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作。还可以实现文件的上传、下载、修改权限、重命名之类的功能。
paramiko包中有如下这些模块。
paramiko下有这些模块
要实现文件的上传下载需要用到的是:
Client: SSH 客户端和秘钥策略
Transport: Core protocol implementation
SFTP: 根据ssh传输协议的sftp会话,实现远程文件操作,如上传、下载、权限、状态。

安装paramiko

pip3 install paramiko
pip install paramiko

2、Transport

2.1用户名和密码登录

# 实例化一个transport对象
trans = paramiko.Transport(('192.168.2.129', 22))
# 建立连接
trans.connect(username='super', password='super')

# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans
# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())

# 关闭连接
trans.close()

2.2公钥密钥登录

# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 建立连接
trans = paramiko.Transport(('192.168.2.129', 22))
trans.connect(username='super', pkey=pkey)

# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans

# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())

# 实例化一个 sftp对象,指定连接的通道
sftp = paramiko.SFTPClient.from_transport(trans)
# 发送文件
sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')
# 下载文件
# sftp.get(remotepath, localpath)

3、SSHClient

SSHClient即是paramiko.client.SSHClient。SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),是用来处理身份验证和建立通信通道,通常用于执行远程命令。
登录远程服务器可以通过SSHClient和Transport两种方式来实现。

3.1用户名和密码登录

# 建立一个sshclient对象
ssh = paramiko.SSHClient()
# 允许将信任的主机自动加入到host_allow 列表,此方法必须放在connect方法的前面
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 调用connect方法连接服务器
ssh.connect(hostname='192.168.2.129', port=22, username='super', password='super')
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read().decode())
# 关闭连接
ssh.close()

3.2公钥密钥登录

# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 建立连接
ssh = paramiko.SSHClient()
ssh.connect(hostname='192.168.2.129',
            port=22,
            username='super',
            pkey=pkey)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read().decode())
# 关闭连接
ssh.close()

例子如下:

client = SSHClient() # 建立客户端实例
client.load_system_host_keys() # 加载系统秘钥
client.connect('ssh.example.com') # 连接远程服务器
stdin, stdout, stderr = client.exec_command('ls -l') # 需要执行的远程命令

4、SFTPClient

SFTPClient的作用类似与Linux的sftp命令,是对SFTP客户端的封装,用以实现远程文件操作,如文件上传、下载、修改文件权限等操作。
SFTPCLient作为一个sftp的客户端对象,根据ssh传输协议的sftp会话,实现远程文件操作,如上传、下载、权限、状态。
常用的有如下这些方法:

from_transport(cls,t) 创建一个已连通的SFTP客户端通道
put(localpath, remotepath, callback=None, confirm=True) 将本地文件上传到服务器 参数confirm:是否调用stat()方法检查文件状态,返回ls -l的结果
get(remotepath, localpath, callback=None) 从服务器下载文件到本地
mkdir() 在服务器上创建目录
remove() 在服务器上删除目录
rename() 在服务器上重命名目录
stat() 查看服务器文件状态
listdir() 列出服务器目录下的文件

5、代码实例

#coding:utf-8
#@author:sjl
#@created:2019/01/14
#@updated:2019/01/25
#@des: 实现文件的上传、下载等功能


import paramiko
import os
import time
import datetime

host = "1.1.1.1"  # 远程服务器ip
user = "root" # 远程服务器用户名
password = "123456" # 远程服务器密码
port = 22
local_put_path = "/root/test/send_path" # 需要上传的文件放在此目录
local_get_path = "/root/test/rec_path" # 从远程服务器下载的文件放在此目录
remote_put_path = "/root/test/remote_put_path" # 上传的文件放在远程服务器的此目录
remote_get_path = "/root/test/remote_get_path" # 从远程服务器的此目录下载文件

class Pysftp(object):
    """
    python3 自动上传、下载文件
    """
    global local_put_path, local_get_path, remote_put_path, remote_get_path

    def __init__(self, host, port, user, password):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        
    def connect(self):
        """
        建立ssh连接
        """
        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.ssh.connect(self.host, self.port, self.user, self.password)
        print("连接已建立")

    def cmd (self, cmd):
    	"""
    	需要执行的命令
    	"""
        #cmd = "date"
        stdin, stdout, stderr = self.ssh.exec_command(cmd)
        print(stdout.read().decode("utf8"))

    def mkdir(self):
        """
        创建本地文件夹,存放上传、下载的文件
        """
        for lp in [local_put_path, local_get_path]:
            if not os.path.exists(lp):
                os.makedirs(lp, 666)
                print("创建本地文件夹:{}".format(lp))
            else:
                print("本地文件夹:{}已存在".format(lp))

    def put(self):
        """
        上传文件
        """
        sftp = paramiko.SFTPClient.from_transport(self.ssh.get_transport())
        # sftp = self.ssh.open_sftp()
        for root, dirs, files in os.walk(local_put_path):
            for fname in files:
                local_full_name = os.path.join(root, fname)
                local_done_write(local_full_name)   # 本地文件已写入完成,可以上传了
                sftp.put(local_full_name, os.path.join(remote_put_path, fname))
                os.remove(local_full_name)
                print("{}\n上传成功:本地文件:{}====>远程{}:{},已删除该本地文件\n".format(datetime.datetime.now(), local_full_name, self.host, remote_put_path))

    def get(self):
        """
        下载文件
        """
        sftp = paramiko.SFTPClient.from_transport(self.ssh.get_transport())
        # sftp = self.ssh.open_sftp() #  在ssh服务器上开启一个sftp会话
        for fname in sftp.listdir(remote_get_path):
            try:
                #if fname[:7] == 'result-': # 文件名以'result-'开头才下载,但是不够优雅
                if fname.startwith('result-'): # 贼拉优雅了
                    remote_full_name = os.path.join(remote_get_path, fname)
                    self.remote_done_transffer(remote_full_name) 
                    sftp.get(remote_full_name, os.path.join(local_get_path, fname))
                    sftp.remove(remote_full_name)
                    print("[{}]下载成功:远程文件{}:{}====>本地{},已删除该远程文件\n".format(datetime.datetime.now(), self.host, remote_full_name, local_get_path))
            except Exception as e:
                print(e)
                
    def stat(self, fpath):
        """
        检查远程服务器文件状态
        :param fpath:文件绝对路径
        """
        sftp = paramiko.SFTPClient.from_transport(self.ssh.get_transport())
        # sftp = self.ssh.open_sftp()
        return sftp.stat(fpath)

    def remote_done_transffer(self, fpath):
        """
        检查文件是否传输完成
        :param fpath:远程服务器上待下载文件绝对路径
        """
        while True:
            old_size = self.stat(fpath).st_size
            time.sleep(3)
            new_size = self.stat(fpath).st_size
            if new_size <= old_size: # 传输已完成
                return

    def close(self):
        """
        关闭ssh连接
        """
        self.ssh.close()
        print("连接关闭")

    def local_done_write(self, fpath):
        """
        检查本地文件是否已写入完成
        :param fpath:本地待上传文件绝对路径
        """
        while True:
            old_size = os.stat(fpath).st_size
            time.sleep(3)
            new_size = os.stat(fpath).st_size
            if new_size <= old_size:    # 写入已完成
                return

def transffer():
    """传输函数
    """
    global host, port, user, password
    obj = Pysftp(host, port, user, password)
    obj.connect()
    obj.mkdir()
    while True:
        # obj.cmd()
        obj.put()
        obj.get()
        time.sleep(5)


if __name__ == '__main__':
     transffer()

6、参考文献

[1]: Python模块学习 - Paramiko
[2]: 麦子学院paramiko基础
[3]: python模块之 paramiko
[4]: paramiko官方文档

  • 9
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值