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

我正在使用一个简单的工具,该工具使用密码也将密码传输到文​​件的硬编码位置。我是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.'

再次感谢!

I’m working on a simple tool that transfers files to a hard-coded location with the password also hard-coded. I’m a python novice, but thanks to ftplib, it was easy:

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)

The problem is that I can’t find any library that supports sFTP. What’s the normal way to do something like this securely?

Edit: Thanks to the answers here, I’ve gotten it working with Paramiko and this was the syntax.

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.'

Thanks again!


回答 0

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

Paramiko supports SFTP. I’ve used it, and I’ve used Twisted. Both have their place, but you might find it easier to start with Paramiko.


回答 1

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

You should check out pysftp https://pypi.python.org/pypi/pysftp it depends on paramiko, but wraps most common use cases to just a few lines of code.

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.'

回答 2

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

大功告成!:)

If you want easy and simple, you might also want to look at Fabric. It’s an automated deployment tool like Ruby’s Capistrano, but simpler and of course for Python. It’s build on top of Paramiko.

You might not want to do ‘automated deployment’ but Fabric would suit your use case perfectly none the less. To show you how simple Fabric is: the fab file and command for your script would look like this (not tested, but 99% sure it will work):

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

Then run the file with the fab command:

fab -f fab_putfile.py put_file:file=./path/to/my/file

And you’re 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 这里

Here is a sample using pysftp and a private key.

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 is an easy to use sftp module that utilizes paramiko and pycrypto. It provides a simple interface to sftp.. Other things that you can do with pysftp which are quite useful:

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

More commands and about PySFTP here.


回答 4

Twisted可以帮助您完成您的工作,查看他们的文档,其中有很多示例。它也是一种成熟的产品,背后有庞大的开发人员/用户社区。

Twisted can help you with what you are doing, check out their documentation, there are plenty of examples. Also it is a mature product with a big developer/user community behind it.


回答 5

使用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)

With RSA Key then refer here

Snippet:

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)

回答 6

有很多关于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

There are a bunch of answers that mention pysftp, so in the event that you want a context manager wrapper around pysftp, here is a solution that is even less code that ends up looking like the following when used

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.") 

The (fuller) example: http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

This context manager happens to have auto-retry logic baked in in the event you can’t connect the first time around (which surprisingly happens more often than you’d expect in a production environment…)

The context manager gist for open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515


回答 7

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

Paramiko is so slow. Use subprocess and shell, here is an example:

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)

回答 8

带有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(...

PyFilesystem with its sshfs is one option. It uses Paramiko under the hood and provides a nicer paltform independent interface on top.

import fs

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

or

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

回答 9

您可以使用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')

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

You can use the pexpect module

Here is a good intro post

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')

I haven’t tested this but it should work


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。