Python中的SFTP?(与平台无关)


181

我正在使用一个简单的工具,该工具使用密码也将密码传输到文​​件的硬编码位置。我是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
谢谢 !在5分钟内获得了一个SFTP上传脚本:)
Ohad Schneider 2010年

1
只是关于原始问题的一般说明,即python ftplib也支持FTPS-TLS上的ftp en.m.wikipedia.org/wiki/FTPS。可以说,在Unix世界中,FTPS服务器的使用较少,部分原因是ssh / sftp的无处不在,但是在Windows环境中,FTPS更为常见,因此sftp服务器的使用要少得多。
Gnudiff

看起来在Python 3.2中添加了FTPS支持,带有扩展的类:类ftplib.FTP_TLS(host ='',user ='',passwd ='',acct ='',keyfile = None,certfile = None,context =无,超时=无,
source_address

Answers:


109

Paramiko支持SFTP。我已经使用过了,并且已经使用过Twisted。两者都有自己的位置,但是您可能会发现从Paramiko开始更容易。


2
是的,paramiko是要走的路(超级好用),要找到依赖的pycrypto的Windows包有点棘手。
毛里

谢谢。由于自述文件中缺少安装说明,我花了一些时间来弄清楚如何安装软件包,但这正是我所需要的!
Mark Wilbur

15
请参阅bitprophet.org/blog/2012/09/29/paramiko-and-ssh,其中Jeff Forcier解释说ssh已过时,而paramiko是前进的方向。
克里斯托弗·马汉

2
还有基于
Paramiko


76

您应该查看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.'

4
with在示例中投票
Roman Podlinov

2
pip install pysftp
鲍勃·斯坦因

2
是否可以选择将新的sftp主机自动添加到已知主机?
user443854 '16

1
@ user443854是的,有pysftp.readthedocs.io/en/release_0.2.9/…但是我绝对不建议这样做,尽管您可以添加另一个known_host文件
AsTeR

15

如果您想要简单易用,则可能还需要查看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

大功告成!:)


12

这是使用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 这里


srv.get(file_path) # Download a file from remote server你能解释其中它下载文件到?
Markus Meskanen

您是否尝试过为您执行处决?
radtek

是的,但是文件系统在哪里?一切顺利,但是我似乎无法从任何地方找到文件。
马库斯·梅斯卡宁

抱歉,我的意思是本地目录。尝试从主目录执行脚本,然后查看文件是否存在。
radtek


1

使用RSA密钥,然后在这里参考

片段:

import pysftp
import paramiko
from base64 import decodebytes

keydata = b"""L+WsiL5VL51ecJi3LVjmblkAdUTU+xbmXmUArIU5+8N6ua76jO/+T""" 
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)

0

有很多关于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_sftphttps : //gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515


0

帕拉米科太慢了。使用子进程和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)

问题是关于“ Python”的问题,它通常意味着要坚持使用它-特别是在有很多选择的时候。不过,更重要的是,它表示“平台无关”。我不能说你的答案是否更快。也许?
BuvinJ

0

带有sshfs的PyFilesystem是一种选择。它在后台使用了Paramiko,并在顶部提供了一个更好的paltform独立界面。

import fs

sf = fs.open_fs("sftp://[user[:password]@]host[:port]/[directory]")
sf.makedir('my_dir')

要么

from fs.sshfs import SSHFS
sf = SSHFS(...

-1

您可以使用pexpect模块

这是一个很好的介绍性帖子

child = pexpect.spawn ('/usr/bin/sftp ' + user@ftp.site.com )
child.expect ('.* password:')
child.sendline (your_password)
child.expect ('sftp> ')
child.sendline ('dir')
child.expect ('sftp> ')
file_list = child.before
child.sendline ('bye')

我没有测试过,但应该可以

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.