python使用paramiko实现远程文件的上传下载
1、简述paramiko
py2和py3都可以使用这个模块。它是通过SSH2协议(底层使用cryptography)??来与远程服务器建立安全(加密和认证)连接的。与SSL(aka TLS)不同的是,SSH2协议不需要由强大的中央机构签署的分层证书。另外需要知道的是,为了安全访问远程shell,才使用SSH2协议替换Telnet和rsh,而且SSH2协议还具有通过加密隧道向远程服务打开任意通道的能力(例如,这是SFTP的工作方式)。(抱歉,英语不太过关,这个翻译的有些生硬)
通过使用Paramiko,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作。还可以实现文件的上传、下载、修改权限、重命名之类的功能。
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官方文档