SFTP en Python? (indépendant de la plateforme)

181

Je travaille sur un outil simple qui transfère les fichiers vers un emplacement codé en dur avec le mot de passe également codé en dur. Je suis novice en python, mais grâce à ftplib, c'était 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)

Le problème est que je ne trouve aucune bibliothèque prenant en charge sFTP. Quelle est la manière normale de faire quelque chose comme ça en toute sécurité?

Edit: Grâce aux réponses ici, je l'ai fait fonctionner avec Paramiko et c'était la syntaxe.

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

Merci encore!

Mark Wilbur
la source
1
Merci ! Vous avez un script de téléchargement SFTP fonctionnant en 5 minutes :)
Ohad Schneider
1
Juste une note générale sur la question originale que python ftplib prend également en charge FTPS - ftp sur TLS en.m.wikipedia.org/wiki/FTPS . Les serveurs FTPS sont sans doute moins utilisés dans le monde Unix, en partie à cause de l'omniprésence de ssh / sftp, cependant, les serveurs sftp sont beaucoup moins présents dans l'environnement Windows, où FTPS est plus courant.
Gnudiff
On dirait que la prise en charge FTPS a été ajoutée dans Python 3.2 avec une source de classe étendue : class ftplib.FTP_TLS (host = '', user = '', passwd = '', acct = '', keyfile = None, certfile = None, context = None, timeout = None, source_address = None)
mgrollins

Réponses:

109

Paramiko prend en charge SFTP. Je l'ai utilisé et j'ai utilisé Twisted. Les deux ont leur place, mais vous trouverez peut-être plus facile de commencer avec Paramiko.

Brian Clapper
la source
2
yepp, paramiko est la voie à suivre (super facile à utiliser), c'est un peu difficile de trouver le paquet windows de pycrypto qui est une dépendance.
Mauli
Je vous remercie. Il m'a fallu un certain temps pour comprendre comment installer le package en raison du manque d'instructions d'installation dans le fichier Lisez-moi, mais c'était exactement ce dont j'avais besoin!
Mark Wilbur
15
Voir bitprophet.org/blog/2012/09/29/paramiko-and-ssh dans lequel Jeff Forcier explique que ssh est obsolète et que le paramiko est la voie à suivre.
Christopher Mahan
2
Il y a aussi code.google.com/p/pysftp qui est basé sur Paramiko, mais plus facile à utiliser
franzlorenzon
78

Vous devriez vérifier pysftp https://pypi.python.org/pypi/pysftp cela dépend de paramiko, mais encapsule les cas d'utilisation les plus courants à quelques lignes de code.

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
la source
4
Votez pour withl'exemple
Roman Podlinov
2
pip install pysftp
Bob Stein
2
Existe-t-il une option pour ajouter automatiquement un nouvel hôte sftp aux hôtes connus?
user443854
1
@ user443854 oui il y a pysftp.readthedocs.io/en/release_0.2.9/... Mais je ne recommanderais certainement pas cela, bien que vous puissiez ajouter un autre fichier
known_host
15

Si vous voulez facile et simple, vous voudrez peut-être aussi regarder Fabric . C'est un outil de déploiement automatisé comme Ruby's Capistrano, mais plus simple et bien sûr pour Python. Il est construit sur Paramiko.

Vous ne voudrez peut-être pas faire de `` déploiement automatisé '', mais Fabric conviendrait parfaitement à votre cas d'utilisation néanmoins. Pour vous montrer à quel point Fabric est simple: le fichier fab et la commande de votre script ressembleraient à ceci (non testé, mais sûr à 99% que cela fonctionnera):

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

Ensuite, exécutez le fichier avec la commande fab:

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

Et tu as fini! :)

hopla
la source
12

Voici un exemple utilisant pysftp et une clé privée.

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 est un module sftp facile à utiliser qui utilise paramiko et pycrypto. Il fournit une interface simple à sftp .. D'autres choses que vous pouvez faire avec pysftp qui sont très utiles:

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

Plus de commandes et sur PySFTP ici .

Radtek
la source
srv.get(file_path) # Download a file from remote serverpouvez-vous expliquer télécharge le fichier?
Markus Meskanen
Avez-vous essayé le local pour vous exécuté?
radtek
Ouais mais où sur le système de fichiers? Tout se passe correctement mais je n'arrive pas à trouver le fichier de n'importe où.
Markus Meskanen
Désolé je voulais dire local dir. Essayez d'exécuter le script à partir de votre répertoire personnel et de voir si le fichier est là.
radtek
1

Avec RSA Key puis référez-vous ici

Fragment:

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
la source
0

Il y a un tas de réponses qui mentionnent pysftp, donc si vous voulez un wrapper de gestionnaire de contexte autour de pysftp, voici une solution qui est encore moins de code qui finit par ressembler à ce qui suit lorsqu'il est utilisé

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

L'exemple (plus complet): http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

Il se trouve que ce gestionnaire de contexte a une logique de relance automatique intégrée dans le cas où vous ne pouvez pas vous connecter la première fois (ce qui se produit étonnamment plus souvent que prévu dans un environnement de production ...)

L'essentiel du gestionnaire de contexte pour open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515

prschmid
la source
0

Paramiko est si lent. Utilisez le sous-processus et le shell, voici un exemple:

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 source
La question concerne "Python", ce qui implique généralement de s'en tenir à cela - surtout quand il y a tellement d'options pour le faire. Plus important encore, il dit "Indépendant de la plate-forme". Je ne peux pas dire si votre réponse fonctionne plus rapidement ou pas. Peut-être?
BuvinJ
0

PyFilesystem avec ses sshfs est une option. Il utilise Paramiko sous le capot et fournit une interface indépendante de la palette plus agréable sur le dessus.

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
la source
-1

Vous pouvez utiliser le module pexpect

Voici un bon post d'introduction

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

Je n'ai pas testé ça mais ça devrait marcher

MIkee
la source