SFTP in Python? (Plattformunabhängig)


180

Ich arbeite an einem einfachen Tool, das Dateien an einen fest codierten Speicherort überträgt, wobei das Kennwort ebenfalls fest codiert ist. Ich bin ein Python-Neuling, aber dank ftplib war es einfach:

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)

Das Problem ist, dass ich keine Bibliothek finden kann, die sFTP unterstützt. Was ist der normale Weg, um so etwas sicher zu machen?

Edit: Dank der Antworten hier habe ich es mit Paramiko zum Laufen gebracht und dies war die Syntax.

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

Danke noch einmal!


1
Vielen Dank ! Ein SFTP-Upload-Skript funktioniert in 5 Minuten :)
Ohad Schneider

1
Nur eine allgemeine Anmerkung zur ursprünglichen Frage, dass Python ftplib auch FTPS unterstützt - ftp über TLS en.m.wikipedia.org/wiki/FTPS . FTPS-Server werden in der Unix-Welt wahrscheinlich weniger verwendet, was teilweise auf die Allgegenwart von ssh / sftp zurückzuführen ist. Sftp-Server sind jedoch in Windows-Umgebungen, in denen FTPS häufiger vorkommt, viel weniger vorhanden.
Gnudiff

Sieht aus wie FTPS Unterstützung wurde in Python 3.2 mit einer erweiterten Klasse hinzugefügt Quelle Klasse ftplib.FTP_TLS (host = '', user = '', passwd = '', acct = '', keyfile = None, certfile = None, context =: Keine, Zeitüberschreitung = Keine, Quelladresse = Keine)
Mgrollins

Antworten:


108

Paramiko unterstützt SFTP. Ich habe es benutzt und ich habe Twisted benutzt. Beide haben ihren Platz, aber es fällt Ihnen vielleicht leichter, mit Paramiko zu beginnen.


2
yepp, paramiko ist der richtige Weg (super einfach zu bedienen), es ist etwas schwierig, das Windows-Paket von pycrypto zu finden, das eine Abhängigkeit darstellt.
Mauli

Danke dir. Es dauerte eine Weile, bis ich herausgefunden hatte, wie das Paket installiert werden sollte, da in der Readme-Datei keine Installationsanweisungen vorhanden waren, aber es war genau das, was ich brauchte!
Mark Wilbur

15
Siehe bitprophet.org/blog/2012/09/29/paramiko-and-ssh, in dem Jeff Forcier erklärt, dass ssh veraltet und paramiko der Weg in die Zukunft ist.
Christopher Mahan

2
Es gibt auch code.google.com/p/pysftp, das auf Paramiko basiert, aber einfacher zu bedienen ist
franzlorenzon


76

Sie sollten sich pysftp https://pypi.python.org/pypi/pysftp ansehen, es hängt von paramiko ab, aber die meisten Anwendungsfälle werden auf nur wenige Codezeilen beschränkt.

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
with
Stimmen Sie

2
pip install pysftp
Bob Stein

2
Gibt es eine Option, um bekannten Hosts automatisch einen neuen SFTP-Host hinzuzufügen?
user443854

1
@ user443854 ja, es gibt pysftp.readthedocs.io/en/release_0.2.9/… Aber ich würde das definitiv nicht empfehlen, obwohl Sie eine andere bekannte_Host-Datei hinzufügen können
AsTeR

15

Wenn Sie einfach und unkompliziert sein möchten, sollten Sie sich auch Fabric ansehen . Es ist ein automatisiertes Bereitstellungstool wie Ruby's Capistrano, aber einfacher und natürlich für Python. Es baut auf Paramiko auf.

Möglicherweise möchten Sie keine automatisierte Bereitstellung durchführen, aber Fabric passt trotzdem perfekt zu Ihrem Anwendungsfall. Um Ihnen zu zeigen, wie einfach Fabric ist: Die Fab-Datei und der Befehl für Ihr Skript würden folgendermaßen aussehen (nicht getestet, aber zu 99% sicher, dass es funktioniert):

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

Führen Sie dann die Datei mit dem Befehl fab aus:

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

Und du bist fertig! :) :)


12

Hier ist ein Beispiel mit pysftp und einem privaten Schlüssel.

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 ist ein einfach zu bedienendes sftp-Modul, das paramiko und pycrypto verwendet. Es bietet eine einfache Schnittstelle zu sftp. Andere Dinge, die Sie mit pysftp tun können, die sehr nützlich sind:

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

Weitere Befehle und Informationen zu PySFTP finden Sie hier .


srv.get(file_path) # Download a file from remote serverKönnen Sie erklären, wohin die Datei heruntergeladen wird?
Markus Meskanen

Haben Sie versucht, die lokale für Sie ausgeführt?
Radtek

Ja, aber wo im Dateisystem? Alles läuft erfolgreich ab, aber ich kann die Datei anscheinend nirgendwo finden.
Markus Meskanen

Entschuldigung, ich meinte lokales Verzeichnis. Versuchen Sie, das Skript von Ihrem Home-Verzeichnis aus auszuführen und festzustellen, ob die Datei vorhanden ist.
Radtek


1

Mit RSA Key dann hier verweisen

Snippet:

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

Es gibt eine Reihe von Antworten, in denen pysftp erwähnt wird. Wenn Sie also einen Kontextmanager-Wrapper für pysftp benötigen, finden Sie hier eine Lösung, die noch weniger Code enthält und bei Verwendung wie folgt aussieht

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

Das (ausführlichere) Beispiel: http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

In diesem Kontextmanager ist zufällig eine Logik für die automatische Wiederholung integriert, falls Sie beim ersten Mal keine Verbindung herstellen können (was überraschenderweise häufiger vorkommt, als Sie es in einer Produktionsumgebung erwarten würden ...).

Der Kontextmanager enthält folgende Informationen open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515


0

Paramiko ist so langsam. Verwenden Sie Unterprozess und Shell. Hier ein Beispiel:

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)

Die Frage bezieht sich auf "Python", was im Allgemeinen bedeutet, daran festzuhalten - insbesondere, wenn es so viele Möglichkeiten dafür gibt. Noch wichtiger ist jedoch "Plattformunabhängig". Ich kann nicht sagen, ob Ihre Antwort schneller funktioniert oder nicht. Vielleicht?
BuvinJ

0

PyFilesystem mit seinen sshfs ist eine Option. Es verwendet Paramiko unter der Haube und bietet darüber hinaus eine schönere, paltformunabhängige Oberfläche.

import fs

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

oder

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

-1

Sie können das pexpect-Modul verwenden

Hier ist ein guter Intro-Beitrag

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

Ich habe das nicht getestet, aber es sollte funktionieren

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.