SFTP w Pythonie? (niezależne od platformy)

181

Pracuję nad prostym narzędziem, które przesyła pliki do zakodowanej lokalizacji z hasłem również zakodowanym na stałe. Jestem nowicjuszem w Pythonie, ale dzięki ftplib było łatwo:

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)

Problem w tym, że nie mogę znaleźć żadnej biblioteki obsługującej sFTP. Jaki jest normalny sposób na bezpieczne wykonanie czegoś takiego?

Edycja: Dzięki odpowiedziom tutaj, udało mi się to współpracować z Paramiko i taka była składnia.

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

Dzięki jeszcze raz!

Mark Wilbur
źródło
1
Dzięki ! Mam skrypt przesyłania SFTP działający w 5 minut :)
Ohad Schneider.
1
Tylko ogólna uwaga na temat pierwotnego pytania, że ​​ftplib w pythonie obsługuje również FTPS - ftp przez TLS en.m.wikipedia.org/wiki/FTPS . Serwery FTPS są prawdopodobnie rzadziej używane w świecie Uniksa, częściowo z powodu wszechobecności ssh / sftp, jednak serwery sftp są znacznie rzadziej obecne w środowisku Windows, gdzie FTPS jest bardziej powszechny.
Gnudiff
Wygląda na to, że obsługa FTPS została dodana w Pythonie 3.2 z rozszerzonym źródłem klasy : class ftplib.FTP_TLS (host = '', user = '', passwd = '', acct = '', keyfile = None, certfile = None, context = None, timeout = None, source_address = None)
mgrollins,

Odpowiedzi:

109

Paramiko obsługuje SFTP. Użyłem go i użyłem Twisted. Oba mają swoje miejsce, ale może być łatwiej zacząć od Paramiko.

Brian Clapper
źródło
2
tak, paramiko to droga (bardzo łatwa w użyciu), trochę trudno jest znaleźć pakiet pycrypto dla systemu Windows, który jest zależnością.
Mauli,
Dziękuję Ci. Zajęło mi trochę czasu, zanim wymyśliłem, jak zainstalować pakiet ze względu na brak instrukcji instalacji w pliku readme, ale właśnie tego potrzebowałem!
Mark Wilbur
15
Zobacz bitprophet.org/blog/2012/09/29/paramiko-and-ssh, w którym Jeff Forcier wyjaśnia, że ​​ssh jest przestarzały, a paramiko to droga naprzód.
Christopher Mahan,
2
Jest też code.google.com/p/pysftp, który jest oparty na Paramiko, ale jest łatwiejszy w użyciu
franzlorenzon,
78

Powinieneś sprawdzić pysftp https://pypi.python.org/pypi/pysftp , zależy to od paramiko, ale zawija większość typowych przypadków użycia tylko do kilku linii kodu.

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
źródło
4
Głosuj na withprzykład
Roman Podlinov 24.07.14
2
pip install pysftp
Bob Stein
2
Czy istnieje opcja automatycznego dodawania nowego hosta sftp do znanych hostów?
user443854
1
@ user443854 tak, jest pysftp.readthedocs.io/en/release_0.2.9/ ... Ale zdecydowanie nie polecam tego, chociaż możesz dodać kolejny plik known_host
AsTeR
15

Jeśli chcesz, aby było łatwe i proste, możesz również spojrzeć na Fabric . Jest to zautomatyzowane narzędzie do wdrażania, takie jak Ruby's Capistrano, ale prostsze i oczywiście dla Pythona. Jest zbudowany na szczycie Paramiko.

Możesz nie chcieć wykonywać „automatycznego wdrażania”, ale mimo to Fabric idealnie pasowałby do Twojego przypadku użycia. Aby pokazać, jak prosty jest Fabric: plik fab i polecenie dla twojego skryptu wyglądałyby następująco (nie testowane, ale na 99% to zadziała):

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

Następnie uruchom plik poleceniem fab:

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

I jesteś skończony! :)

hopla
źródło
12

Oto przykład wykorzystujący pysftp i klucz prywatny.

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 to łatwy w użyciu moduł sftp, który wykorzystuje paramiko i pycrypto. Zapewnia prosty interfejs do sftp. Inne rzeczy, które możesz zrobić z pysftp, które są całkiem przydatne:

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

Więcej poleceń i o PySFTP tutaj .

radtek
źródło
srv.get(file_path) # Download a file from remote serverczy możesz wyjaśnić, skąd pobiera plik?
Markus Meskanen
Czy wypróbowałeś lokalną egzekucję?
radtek
Tak, ale gdzie w systemie plików? Wszystko przebiega pomyślnie, ale nie mogę znaleźć pliku z dowolnego miejsca.
Markus Meskanen,
Przepraszam, miałem na myśli lokalny reż. Spróbuj uruchomić skrypt z katalogu domowego i sprawdź, czy plik tam jest.
radtek
1

Z kluczem RSA zapoznaj się tutaj

Skrawek:

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
źródło
0

Istnieje kilka odpowiedzi, które wspominają o pysftp, więc jeśli chcesz otokować menedżera kontekstu wokół pysftp, oto rozwiązanie, które zawiera jeszcze mniej kodu, który po użyciu wygląda jak poniżej

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

(Pełniejszy) przykład: http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

Ten menedżer kontekstu ma zapisaną logikę automatycznej ponownej próby na wypadek, gdybyś nie mógł połączyć się za pierwszym razem (co zaskakująco zdarza się częściej niż można się spodziewać w środowisku produkcyjnym ...)

Istota menedżera kontekstu dla open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515

prschmid
źródło
0

Paramiko jest taka powolna. Użyj podprocesu i powłoki, oto przykład:

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)
杨 李思
źródło
Pytanie dotyczy „Pythona”, co generalnie implikuje trzymanie się tego - zwłaszcza gdy jest tak wiele możliwości zrobienia tego. Co ważniejsze, jest tam napisane „niezależne od platformy”. Nie mogę jednak powiedzieć, czy twoja odpowiedź działa szybciej, czy nie. Być może?
BuvinJ
0

PyFilesystem z jego sshfs jest jedną z opcji. Wykorzystuje Paramiko pod maską i zapewnia ładniejszy niezależny interfejs na górze.

import fs

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

lub

from fs.sshfs import SSHFS
sf = SSHFS(...
fmalina
źródło
-1

Możesz użyć modułu pexpect

Oto dobry post wprowadzający

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

Nie testowałem tego, ale powinno działać

MIkee
źródło