SFTP в Python? (платформо-независимый)


Я работаю над простым инструментом, который передает файлы в жестко закодированное место с паролем, также жестко закодированным. Я новичок 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. Каков нормальный способ сделать что-то подобное безопасно?

Edit: благодаря ответам здесь, я получил его работать с 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.'

еще раз спасибо!

9 154

9 ответов:

Парамико поддерживает SFTP. Я использовал его, и я использовал Twisted. У обоих есть свое место, но вам может быть легче начать с Парамико.

вы должны проверить 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.'

Если вы хотите легко и просто, вы также можете посмотреть ткани. Это автоматизированный инструмент развертывания, такой как Ruby'S Capistrano, но более простой и ofc ourse для Python. Он построен на вершине Парамико.

возможно, вы не захотите делать "автоматическое развертывание", но 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

и вы сделали! :)

вот пример использования 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 здесь.

Twisted может помочь вам с тем, что вы делаете, проверить их документацию, есть много примеров. Также это зрелый продукт с большим сообществом разработчиков/пользователей за ним.

можно использовать модуль 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')

Я не проверял это, но он должен работать

Парамико так медленно. Используйте подпроцесс и оболочку, вот пример:

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)

С ключом 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)

есть куча ответов, которые упоминают pysftp, поэтому в случае, если вам нужна оболочка context manager вокруг 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

этот контекстный менеджер имеет логику автоматического повтора, запеченную в случае, если вы не можете подключиться в первый раз (что удивительно происходит чаще, чем можно было бы ожидать в производственной среде...)

контекстный менеджер gist для open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515