Python 中的 SFTP?(平台独立)
- 2025-01-22 08:45:00
- admin 原创
- 76
问题描述:
我正在开发一个简单的工具,可以将文件传输到硬编码位置,密码也是硬编码的。我是 Python 新手,但多亏了 ftplib,这很容易:
import ftplib
info= ('someuser', 'password') #hard-coded
def putfile(file, site, dir, user=(), verbose=True):
"""
upload a file by ftp to a site/directory
login hard-coded, binary transfer
"""
if verbose: print 'Uploading', file
local = open(file, 'rb')
remote = ftplib.FTP(site)
remote.login(*user)
remote.cwd(dir)
remote.storbinary('STOR ' + file, local, 1024)
remote.quit()
local.close()
if verbose: print 'Upload done.'
if __name__ == '__main__':
site = 'somewhere.com' #hard-coded
dir = './uploads/' #hard-coded
import sys, getpass
putfile(sys.argv[1], site, dir, user=info)
问题是我找不到任何支持 sFTP 的库。安全地执行此类操作的正常方法是什么?
编辑:感谢这里的答案,我已经可以与 Paramiko 一起使用它了,这就是语法。
import paramiko
host = "THEHOST.com" #hard-coded
port = 22
transport = paramiko.Transport((host, port))
password = "THEPASSWORD" #hard-coded
username = "THEUSERNAME" #hard-coded
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
import sys
path = './THETARGETDIRECTORY/' + sys.argv[1] #hard-coded
localpath = sys.argv[1]
sftp.put(localpath, path)
sftp.close()
transport.close()
print 'Upload done.'
再次感谢!
解决方案 1:
Paramiko支持 SFTP。我用过它,也用过 Twisted。两者都各有用途,但你可能会发现从 Paramiko 开始更容易。
解决方案 2:
您应该检查 pysftp https://pypi.python.org/pypi/pysftp 它依赖于 paramiko,但将最常见的用例包装到仅几行代码中。
import pysftp
import sys
path = './THETARGETDIRECTORY/' + sys.argv[1] #hard-coded
localpath = sys.argv[1]
host = "THEHOST.com" #hard-coded
password = "THEPASSWORD" #hard-coded
username = "THEUSERNAME" #hard-coded
with pysftp.Connection(host, username=username, password=password) as sftp:
sftp.put(localpath, path)
print 'Upload done.'
解决方案 3:
这是使用 pysftp 和私钥的示例。
import pysftp
def upload_file(file_path):
private_key = "~/.ssh/your-key.pem" # can use password keyword in Connection instead
srv = pysftp.Connection(host="your-host", username="user-name", private_key=private_key)
srv.chdir('/var/web/public_files/media/uploads') # change directory on remote server
srv.put(file_path) # To download a file, replace put with get
srv.close() # Close connection
pysftp 是一个易于使用的 sftp 模块,它利用了 paramiko 和 pycrypto。它为 sftp 提供了一个简单的接口。您可以使用 pysftp 执行其他非常有用的操作:
data = srv.listdir() # Get the directory and file listing in a list
srv.get(file_path) # Download a file from remote server
srv.execute('pwd') # Execute a command on the server
更多关于 PySFTP 的命令和信息请见此处。
解决方案 4:
如果你想要简单易用,你可能还想看看Fabric。它是一种自动化部署工具,类似于 Ruby 的 Capistrano,但更简单,当然适用于 Python。它建立在 Paramiko 之上。
您可能不想进行“自动部署”,但 Fabric 无论如何都非常适合您的用例。为了向您展示 Fabric 有多么简单:脚本的 fab 文件和命令将如下所示(未经测试,但 99% 确定它会起作用):
fab_putfile.py:
from fabric.api import *
env.hosts = ['THEHOST.com']
env.user = 'THEUSER'
env.password = 'THEPASSWORD'
def put_file(file):
put(file, './THETARGETDIRECTORY/') # it's copied into the target directory
然后使用 fab 命令运行该文件:
fab -f fab_putfile.py put_file:file=./path/to/my/file
您已经完成了!:)
解决方案 5:
fsspec是一个很好的选择,它提供了一个类似sftp实现的文件系统。
from fsspec.implementations.sftp import SFTPFileSystem
fs = SFTPFileSystem(host=host, username=username, password=password)
# list a directory
fs.ls("/")
# open a file
with fs.open(file_name) as file:
content = file.read()
还值得注意的是,fsspec 在实现中使用了 paramiko 。
解决方案 6:
使用 RSA 密钥然后参考此处
片段:
import pysftp
import paramiko
from base64 import decodebytes
keydata = b"""AAAAB3NzaC1yc2EAAAADAQABAAABAQDl"""
key = paramiko.RSAKey(data=decodebytes(keydata))
cnopts = pysftp.CnOpts()
cnopts.hostkeys.add(host, 'ssh-rsa', key)
with pysftp.Connection(host=host, username=username, password=password, cnopts=cnopts) as sftp:
with sftp.cd(directory):
sftp.put(file_to_sent_to_ftp)
解决方案 7:
Twisted可以帮助您完成工作,请查看其文档,其中有大量示例。此外,它是一款成熟的产品,背后有庞大的开发人员/用户社区。
解决方案 8:
Paramiko 太慢了。使用 subprocess 和 shell,下面是一个例子:
remote_file_name = "filename"
remotedir = "/remote/dir"
localpath = "/local/file/dir"
ftp_cmd_p = """
#!/bin/sh
lftp -u username,password sftp://ip:port <<EOF
cd {remotedir}
lcd {localpath}
get {filename}
EOF
"""
subprocess.call(ftp_cmd_p.format(remotedir=remotedir,
localpath=localpath,
filename=remote_file_name
),
shell=True, stdout=sys.stdout, stderr=sys.stderr)
解决方案 9:
有很多答案提到了 pysftp,所以如果你想要一个围绕 pysftp 的上下文管理器包装器,这里有一个解决方案,它的代码更少,使用时最终看起来像下面这样
path = "sftp://user:p@ssw0rd@test.com/path/to/file.txt"
# Read a file
with open_sftp(path) as f:
s = f.read()
print s
# Write to a file
with open_sftp(path, mode='w') as f:
f.write("Some content.")
(更完整的) 示例: http: //www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html
如果您第一次无法连接(令人惊讶的是,在生产环境中发生这种情况的频率比您预期的要高...),此上下文管理器恰好具有自动重试逻辑。
上下文管理器要点open_sftp
: https: //gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515
解决方案 10:
PyFilesystem及其sshfs是一种选择。它在底层使用 Paramiko,并在顶层提供更好的独立于平台的接口。
import fs
sf = fs.open_fs("sftp://[user[:password]@]host[:port]/[directory]")
sf.makedir('my_dir')
或者
from fs.sshfs import SSHFS
sf = SSHFS(...
解决方案 11:
这是一个通用函数,它将把任何给定的 sftp url 下载到指定路径
from urllib.parse import urlparse
import paramiko
url = 'sftp://username:password@hostname/filepath.txt'
def sftp_download(url, dest):
url = urlparse(url)
with paramiko.Transport((url.hostname, 22)) as transport:
transport.connect(None,url.username,url.password)
with paramiko.SFTPClient.from_transport(transport) as sftp:
sftp.get(url.path, dest)
使用
sftp_download(url, "/tmp/filepath.txt")