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.