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!


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.


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

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! :)


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 .


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)

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


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

-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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.