Python实现SFTP下载
- Python实现SFTP下载
- 基础知识
- paramiko的安装
- SFTP连接
- SFTP下载
- 递归列出所有子目录
- 附赠FTP方法
- 总结
Python实现SFTP下载
上节课讲了通过SFTP软件连接Linux远程下载上传文件。但是,人生苦短,我用python。
基础知识
为什么要用python呢?因为我之前一直用的Fillezilla出现了bug,远程搜索不能搜索文件了,然后我就了解到python也可以实现SSH和SFTP连接,通过编程也能减少重复性的操作。
- paramiko 是python的一个库。通过paramiko我们可以在Python代码中直接使用SSH协议对远程服务器执行操作,而无须通过ssh命令对远程服务器进行操作。
- paramiko包含两个核心组件:SSHClient和SFTPClient
- SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),通常用于执行远程命令。
- SFTPClient的作用类似与Linux的sftp命令,是对SFTP客户端的封装,用以实现远程文件操作,如文件上传、下载、修改文件权限等操作
- ftplib是封装了FTP方法和类的库,这里不做过多介绍。
- python环境建议使用Anaconda下的juyter,开源软件,自行百度安装。
paramiko的安装
如果用的是idle环境,需要在cmd里面安装paramiko库。
win+R → cmd
pip install paramiko
如果装了Anaconda,paramiko和ftplib都是自带的库,直接import即可。
SFTP连接
话不多说,直接上代码
import paramiko
# 获取Transport实例
tran = paramiko.Transport(('10.0.0.3', 22))
# 连接SSH服务端,使用password
tran.connect(username="root", password='123456')
# 获取SFTP实例
sftp = paramiko.SFTPClient.from_transport(tran)
#put(localpath, remotepath, callback=None, confirm=True) 将本地文件上传到服务器 参数confirm:是否调用stat()方法检查文件状态,返回ls -l的结果
#get(remotepath, localpath, callback=None) 从服务器下载文件到本地
#mkdir() 在服务器上创建目录
#remove() 在服务器上删除目录
#rename() 在服务器上重命名目录
#stat() 查看服务器文件状态
#listdir() 列出服务器目录下的文件
#用完记得关了
tran.close()
SFTP下载
import paramiko
import os
#from pathlib import Path
import stat
def DownLoadFileTree(LocalDir, RemoteDir): # 下载整个目录下的文件或文件夹
host="192.168.7.191" #sftp ip
port=22 #sftp端口
sf = paramiko.Transport((host, port))
sf.connect(username="name" , password="123456" )
sftp = paramiko.SFTPClient.from_transport(sf)
if not os.path.exists(LocalDir):
os.makedirs(LocalDir)
files = sftp.listdir_attr(RemoteDir)
for file in files:
if stat.S_ISDIR(file.st_mode):#是否为linux形式目录 true 目录 false 文件
Local = os.path.join(LocalDir, file.filename)
Remote = os.path.join(RemoteDir, file.filename)+"/"
if not os.path.exists(Local):
os.makedirs(Local)
# print("ok")
DownLoadFileTree(host, port, username, password, Local, Remote)
else: # 文件
Local = os.path.join(LocalDir, file.filename)
Remote = RemoteDir+'/'+ file.filename
#print(Remote,'->',Local)
sftp.get(Remote,Local)
sf.close()
把get方法改为put方法,即可类似的实现文件的上传操作。
put(localpath, remotepath)
递归列出所有子目录
def myDir(remote,n=0):
host="192.168.7.191" #sftp ip
port=22 #sftp端口
sf = paramiko.Transport((host, port))
sf.connect(username="name" , password="123456" )
sftp = paramiko.SFTPClient.from_transport(sf)
files = sftp.listdir_attr(remote)
for file in files:
if not stat.S_ISDIR(file.st_mode):
print('\t'*n,file.filename)
else:
print('\t'*n,file.filename+":")
myDir(remote+"/"+file.filename,n+1)
sf.close()
在列出了所有子目录及文件的基础上,可以添加代码筛选自己需要的文件进行下载。
附赠FTP方法
import os
import sys
import ftplib # 定义了FTP类,实现ftp上传和下载
class myFtp:
# 定义一个ftp对象
ftp = ftplib.FTP()
def __init__(self, host, port=21): # 类似c++构造函数
self.ftp.connect(host, port)
# 登陆
def Login(self, user, passwd):
self.ftp.login(user, passwd)
print(self.ftp.welcome) # 打印出欢迎信息
# 下载单个文件
# LocalFile为本地文件路径(带文件名),RemoteFile为ftp文件路径(不带文件名)
def DownLoadFile(self,LocalFile,RemoteFile):
if(os.path.exists(LocalFile)):
os.remove(LocalFile)
file_handler = open(LocalFile, 'wb')
print(file_handler)
# 下载ftp文件
self.ftp.retrbinary('RETR ' + RemoteFile, file_handler.write)
file_handler.close()
return True
# 下载整个目录下的文件
# LocalDir为本地目录(不带文件名),RemoteDir为远程目录(不带文件名)
def DownLoadFileTree(self, LocalDir, RemoteDir):
print("RemoteDir:", RemoteDir)
if not os.path.exists(LocalDir):
os.makedirs(LocalDir)
# 打开该远程目录
self.ftp.cwd(RemoteDir)
# 获取该目录下所有文件名,列表形式
RemoteNames = self.ftp.nlst()
for file in RemoteNames:
Local = os.path.join(LocalDir, file) # 下载到当地的全路径
print(self.ftp.nlst(file)) # [如test.txt]
if file.find(".") == -1: #是否子目录 如test.txt就非子目录
if not os.path.exists(Local):
os.makedirs(Local)
self.DownLoadFileTree(Local, file) # 下载子目录路径
else:
self.DownLoadFile(Local, file)
self.ftp.cwd("..") # 返回路径最外侧
return
# 关闭ftp连接
def close(self):
self.ftp.close()
总结
Filezilla虽然功能强大,但操作仍然有些繁琐。做测试的时候如果需要经常上传、下载、修改文件,还是建议使用python编程,一劳永逸。
好处就是可以下载具有复杂关系的文件,可以把多个线程的结果一并下载。