SFTP in Python? (Piattaforma indipendente)


181

Sto lavorando a un semplice strumento che trasferisce i file in una posizione codificata con la password anch'essa codificata. Sono un principiante di Python, ma grazie a ftplib è stato facile:

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)

Il problema è che non riesco a trovare alcuna libreria che supporti sFTP. Qual è il modo normale di fare qualcosa di simile in modo sicuro?

Modifica: grazie alle risposte qui, l'ho fatto funzionare con Paramiko e questa era la sintassi.

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

Grazie ancora!


1
Grazie ! Ho uno script di upload SFTP funzionante in 5 minuti :)
— Ohad Schneider l'

1
Solo una nota generale sulla domanda originale che Python ftplib supporta anche FTPS - ftp su TLS en.m.wikipedia.org/wiki/FTPS . I server FTPS sono probabilmente meno utilizzati nel mondo Unix, in parte a causa dell'onnipresenza di ssh / sftp, tuttavia i server sftp sono molto meno presenti nell'ambiente Windows, dove FTPS è più comune.
— Gnudiff,

Looks come il supporto FTPS è stato aggiunto in Python 3.2 con una classe estesa fonte : ftplib.FTP_TLS classe (host = '', user = '', passwd = '', Acct = '', keyfile = Nessuno, certfile = Nessuno, context = Nessuno, timeout = Nessuno, indirizzo_origine = Nessuno)
— mgrollins

Risposte:


109

Paramiko supporta SFTP. L'ho usato e ho usato Twisted. Entrambi hanno il loro posto, ma potresti trovare più facile iniziare con Paramiko.


2
Sì, paramiko è la strada da percorrere (super facile da usare), è un po 'complicato trovare il pacchetto windows di pycrypto che è una dipendenza.
— Mauli,

Grazie. Mi ci è voluto un po 'per capire come installare il pacchetto a causa della mancanza di istruzioni di installazione nel file Leggimi, ma era esattamente quello di cui avevo bisogno!
— Mark Wilbur,

15
Vedi bitprophet.org/blog/2012/09/29/paramiko-and-ssh in cui Jeff Forcier spiega che ssh è obsoleto e paramiko è la strada da percorrere.
— Christopher Mahan,

2
C'è anche code.google.com/p/pysftp basato su Paramiko, ma più facile da usare
— franzlorenzon


78

Dovresti dare un'occhiata a pysftp https://pypi.python.org/pypi/pysftp dipende da paramiko, ma racchiude i casi d'uso più comuni in poche righe di codice.

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
Vota in alto withnell'esempio
— Roman Podlinov,

2
pip install pysftp
— Bob Stein,

2
Esiste un'opzione per aggiungere automaticamente un nuovo host sftp a host noti?
— user443854,

1
@ user443854 sì, c'è pysftp.readthedocs.io/en/release_0.2.9/… Ma sicuramente non lo consiglierei, anche se puoi aggiungere un altro file
— known_host

15

Se vuoi essere facile e semplice, potresti anche voler guardare Fabric . È uno strumento di distribuzione automatizzato come Ruby Capistrano, ma più semplice e ovviamente per Python. È costruito su Paramiko.

Potresti non voler fare una "distribuzione automatizzata", ma Fabric si adatterà perfettamente al tuo caso d'uso. Per mostrarti quanto è semplice Fabric: il file fab e il comando per il tuo script sarebbero così (non testati, ma sicuri al 99% che funzionerà):

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

Quindi eseguire il file con il comando fab:

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

E hai finito! :)


12

Ecco un esempio usando pysftp e una chiave privata.

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 è un modulo sftp facile da usare che utilizza paramiko e pycrypto. Fornisce una semplice interfaccia per sftp .. Altre cose che puoi fare con pysftp che sono abbastanza utili:

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

Più comandi e informazioni su PySFTP qui .


srv.get(file_path) # Download a file from remote serverpuoi spiegare dove scarica il file?
— Markus Meskanen,

Hai provato il locale per te eseguito?
— Radtek,

Sì, ma dove si trova il file system? Tutto procede con successo ma non riesco a trovare il file da nessuna parte.
— Markus Meskanen,

Mi dispiace intendevo dir locale. Prova a eseguire lo script dalla tua home directory e vedere se il file è lì.
— Radtek,


1

Con RSA Key quindi fare riferimento qui

Frammento:

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

Ci sono un sacco di risposte che menzionano pysftp, quindi nel caso in cui si desideri un wrapper del gestore di contesto attorno a pysftp, ecco una soluzione che è ancora meno codice che finisce per apparire come il seguente quando usato

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

L'esempio (più completo): http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

Questo gestore del contesto ha una logica di ripetizione automatica inserita nel caso in cui non riesci a connetterti la prima volta (cosa che accade sorprendentemente più spesso di quanto ti aspetteresti in un ambiente di produzione ...)

Il gestore del contesto per open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515


0

Paramiko è così lento. Usa sottoprocesso e shell, ecco un esempio:

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)

La domanda è su "Python", che in genere implica attenersi a ciò - specialmente quando ci sono così tante opzioni per farlo. Ancora più importante, dice "Indipendente dalla piattaforma". Non posso dire se la tua risposta funziona più velocemente o no. Forse?
— BuvinJ

0

PyFilesystem con i suoi sshfs è un'opzione. Utilizza Paramiko sotto il cofano e offre un'interfaccia indipendente con paltform più gradevole.

import fs

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

o

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

-1

È possibile utilizzare il modulo pexpect

Ecco un buon post introduttivo

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

Non l'ho provato ma dovrebbe funzionare

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.