SFTP em Python? (plataforma independente)

181

Estou trabalhando em uma ferramenta simples que transfere arquivos para um local codificado com a senha também codificada. Sou iniciante em python, mas graças ao ftplib, foi fácil:

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)

O problema é que não consigo encontrar nenhuma biblioteca que suporte sFTP. Qual é a maneira normal de fazer algo assim com segurança?

Edit: Graças às respostas aqui, eu consegui trabalhar com a Paramiko e essa foi a sintaxe.

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

Obrigado novamente!

Mark Wilbur
fonte
1
Obrigado ! Tem um roteiro SFTP carregamento trabalhando em 5 minutos :)
Ohad Schneider
1
Apenas uma observação geral sobre a pergunta original de que o python ftplib também suporta FTPS - ftp sobre TLS en.m.wikipedia.org/wiki/FTPS . Os servidores FTPS são indiscutivelmente menos usados ​​no mundo Unix, em parte devido à onipresença do ssh / sftp, no entanto, os servidores sftp estão muito menos presentes no ambiente Windows, onde o FTPS é mais comum.
Gnudiff
Parece que o suporte ao FTPS foi adicionado no Python 3.2 com uma fonte de classe estendida : class ftplib.FTP_TLS (host = '', user = '', passwd = '', acct = '', keyfile = None, certfile = None, context = None, timeout = None, source_address = None)
mgrollins

Respostas:

109

Paramiko suporta SFTP. Eu usei e usei o Twisted. Ambos têm o seu lugar, mas você pode achar mais fácil começar com o Paramiko.

Brian Clapper
fonte
2
sim, paramiko é o caminho a percorrer (super fácil de usar), é um pouco complicado encontrar o pacote windows de pycrypto, que é uma dependência.
11289 Mauli
Obrigado. Demorei um pouco para descobrir como instalar o pacote devido à falta de instruções de instalação no leia-me, mas era exatamente o que eu precisava!
11119 Mark Wilbur
15
Veja bitprophet.org/blog/2012/09/29/paramiko-and-ssh no qual Jeff Forcier explica que o ssh é obsoleto e o paramiko é o caminho a seguir.
Christopher Mahan
2
Há também code.google.com/p/pysftp que se baseia na paramiko, mas mais fácil de usar
franzlorenzon
78

Você deve verificar o pysftp https://pypi.python.org/pypi/pysftp , depende do paramiko, mas agrupa os casos de uso mais comuns em apenas algumas linhas de código.

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.'
Dundee MT
fonte
4
Vote withno exemplo
Roman Podlinov
2
pip install pysftp
Bob Stein
2
Existe uma opção para adicionar automaticamente novo host sftp a hosts conhecidos?
user443854
1
@ user443854 sim, há pysftp.readthedocs.io/en/release_0.2.9/... Mas eu definitivamente não recomendaria que, embora você pode adicionar outro arquivo known_host
Aster
15

Se você quiser fácil e simples, também pode querer olhar para o Fabric . É uma ferramenta de implantação automatizada como o Ruby's Capistrano, mas mais simples e, é claro, para o Python. É construído em cima do Paramiko.

Talvez você não queira fazer uma 'implantação automatizada', mas o Fabric atenderá perfeitamente ao seu caso de uso. Para mostrar como o Fabric é simples: o arquivo e o comando fab do seu script teriam a seguinte aparência (não testado, mas com 99% de certeza de que funcionará):

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

Em seguida, execute o arquivo com o comando fab:

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

E pronto! :)

hopla
fonte
12

Aqui está um exemplo usando pysftp e uma chave privada.

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

O pysftp é um módulo sftp fácil de usar que utiliza paramiko e pycrypto. Ele fornece uma interface simples para o sftp. Outras coisas que você pode fazer com o pysftp são bastante úteis:

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

Mais comandos e sobre PySFTP aqui .

Radtek
fonte
srv.get(file_path) # Download a file from remote servervocê pode explicar para onde ele baixa o arquivo?
Markus Meskanen
Você tentou o local para o qual foi executado?
Radtek
Sim, mas onde no sistema de arquivos? Tudo passa com sucesso, mas não consigo encontrar o arquivo de qualquer lugar.
Markus Meskanen
Desculpe, eu quis dizer dir local. Tente executar o script do seu diretório pessoal e veja se o arquivo está lá.
Radtek
1

Com a chave RSA, consulte aqui

Snippet:

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)
Abhijeet
fonte
0

Há várias respostas que mencionam o pysftp; portanto, no caso de você desejar um wrapper de gerenciador de contexto em torno do pysftp, aqui está uma solução com ainda menos código que acaba parecendo a seguinte quando usado

path = "sftp://user:p@[email protected]/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.") 

O exemplo (mais completo): http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

Esse gerenciador de contexto possui uma lógica de repetição automática ativada caso você não consiga se conectar pela primeira vez (o que surpreendentemente acontece com mais frequência do que você esperaria em um ambiente de produção ...)

A essência do gerenciador de contexto para open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515

prschmid
fonte
0

Paramiko é tão lento. Use subprocesso e shell, aqui está um exemplo:

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)
杨 李思
fonte
A questão é sobre "Python", o que geralmente implica manter isso - especialmente quando existem muitas opções para isso. Mais importante, porém, diz "Independente da plataforma". Não posso dizer se sua resposta funciona mais rápido ou não. Possivelmente?
BuvinJ 29/04
0

O PyFilesystem com seus sshfs é uma opção. Ele usa o Paramiko sob o capô e fornece uma interface independente de paltform melhor na parte superior.

import fs

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

ou

from fs.sshfs import SSHFS
sf = SSHFS(...
fmalina
fonte
-1

Você pode usar o módulo pexpect

Aqui está uma boa introdução

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

Eu não testei isso, mas deve funcionar

MIkee
fonte