SFTP en Python? (plataforma independiente)

181

Estoy trabajando en una herramienta simple que transfiere archivos a una ubicación codificada con la contraseña también codificada. Soy un principiante en python, pero gracias a ftplib, fue 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)

El problema es que no puedo encontrar ninguna biblioteca que admita sFTP. ¿Cuál es la forma normal de hacer algo así de forma segura?

Editar: Gracias a las respuestas aquí, lo conseguí trabajando con Paramiko y esta fue la sintaxis.

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

¡Gracias de nuevo!

Mark Wilbur
fuente
1
Gracias ! Tengo un script de carga SFTP trabajando en 5 minutos :)
Ohad Schneider
1
Solo una nota general sobre la pregunta original que python ftplib también es compatible con FTPS: ftp sobre TLS en.m.wikipedia.org/wiki/FTPS . Los servidores FTPS son posiblemente menos utilizados en el mundo Unix, en parte debido a la omnipresencia de ssh / sftp, sin embargo, los servidores sftp están mucho menos presentes en el entorno de Windows, donde FTPS es más común.
Gnudiff
Parece que el soporte FTPS se agregó en Python 3.2 con una fuente de clase extendida : clase ftplib.FTP_TLS (host = '', user = '', passwd = '', acct = '', keyfile = None, certfile = None, context = None, timeout = None, source_address = None)
mgrollins

Respuestas:

109

Paramiko admite SFTP. Lo he usado y he usado Twisted. Ambos tienen su lugar, pero puede ser más fácil comenzar con Paramiko.

Brian Clapper
fuente
2
sí, paramiko es el camino a seguir (súper fácil de usar), es un poco difícil encontrar el paquete de Windows de pycrypto que es una dependencia.
Mauli
Gracias. Me tomó un tiempo descubrir cómo instalar el paquete debido a la falta de instrucciones de instalación en el archivo Léame, ¡pero era exactamente lo que necesitaba!
Mark Wilbur el
15
Vea bitprophet.org/blog/2012/09/29/paramiko-and-ssh en el que Jeff Forcier explica que ssh está obsoleto y que paramiko es el camino a seguir.
Christopher Mahan
2
También hay code.google.com/p/pysftp, que está basado en Paramiko, pero es más fácil de usar
franzlorenzon
78

Debe consultar pysftp https://pypi.python.org/pypi/pysftp , depende de paramiko, pero ajusta los casos de uso más comunes a solo unas pocas líneas 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
fuente
44
Vote withen el ejemplo
Roman Podlinov
2
pip install pysftp
Bob Stein
2
¿Existe una opción para agregar automáticamente un nuevo host sftp a los hosts conocidos?
user443854
1
@ user443854 sí, hay pysftp.readthedocs.io/en/release_0.2.9/… Pero definitivamente no lo recomendaría, aunque puede agregar otro archivo
conocido_host
15

Si quieres fácil y simple, también puedes mirar Fabric . Es una herramienta de implementación automatizada como Ruby's Capistrano, pero más simple y, por supuesto, para Python. Está construido sobre Paramiko.

Es posible que no desee realizar una 'implementación automatizada', pero Fabric se adaptaría perfectamente a su caso de uso. Para mostrarle lo simple que es Fabric: el archivo fab y el comando para su script se verían así (no probado, pero 99% seguro 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

Luego ejecute el archivo con el comando fab:

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

¡Y tu estas listo! :)

hopla
fuente
12

Aquí hay una muestra usando pysftp y una clave 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

pysftp es un módulo sftp fácil de usar que utiliza paramiko y pycrypto. Proporciona una interfaz simple para sftp. Otras cosas que puede hacer con pysftp que son bastante útiles:

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

Más comandos y sobre PySFTP aquí .

radtek
fuente
srv.get(file_path) # Download a file from remote server¿Puedes explicar dónde descarga el archivo?
Markus Meskanen
¿Probaste el local por el que ejecutaste?
radtek
Sí, pero ¿en qué parte del sistema de archivos? Todo pasa con éxito pero parece que no puedo encontrar el archivo desde ningún lado.
Markus Meskanen
Lo siento, quise decir dir local. Intente ejecutar el script desde su directorio de inicio y vea si el archivo está allí.
radtek
1

Con la clave RSA, consulte aquí

Retazo:

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
fuente
0

Hay un montón de respuestas que mencionan pysftp, por lo que en el caso de que desee un contenedor de administrador de contexto alrededor de pysftp, aquí hay una solución que es aún menos código que termina pareciéndose a lo siguiente cuando se usa

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

El ejemplo (más completo): http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

Este administrador de contexto tiene una lógica de reintento automático en caso de que no pueda conectarse la primera vez (lo que sorprendentemente ocurre con más frecuencia de lo que esperaría en un entorno de producción ...)

La esencia del administrador de contexto para open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515

prschmid
fuente
0

Paramiko es muy lento. Utilice subproceso y shell, aquí hay un ejemplo:

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)
杨 李思
fuente
La pregunta es sobre "Python", lo que generalmente implica quedarse dentro de eso, especialmente cuando hay tantas opciones para hacerlo. Más importante aún, dice "Plataforma independiente". Sin embargo, no puedo decir si tu respuesta funciona más rápido o no. ¿Quizás?
BuvinJ
0

PyFilesystem con sus sshfs es una opción. Utiliza Paramiko debajo del capó y proporciona una interfaz independiente de plataforma más agradable en la parte superior.

import fs

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

o

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

Puedes usar el módulo pexpect

Aquí hay una buena publicación de introducción

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

No he probado esto pero debería funcionar

MIkee
fuente