SFTP em Python? (plataforma independente)
Pergunta
Eu estou trabalhando em uma ferramenta simples que transfere arquivos para um local hard-coded com a senha também hard-coded. Eu sou um novato python, mas graças a ftplib, era fácil:
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)
O problema é que não consigo encontrar qualquer biblioteca que suporta SFTP. Qual é a maneira normal de fazer algo assim de forma segura?
Edit:. Graças às respostas aqui, eu comecei-o a trabalhar com paramiko e esta foi a sintaxe
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.'
Mais uma vez obrigado!
Solução
paramiko suporta SFTP. Eu usei-o, e eu usei torcida. Ambos têm o seu lugar, mas você pode achar que é mais fácil começar com paramiko.
Outras dicas
Você deve verificar se pysftp https://pypi.python.org/pypi/pysftp isso depende de paramiko, mas wraps casos de uso mais comuns para apenas algumas linhas de código.
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.'
Se você quiser fácil e simples, que você pode também querer olhar para Tecido . É uma ferramenta de implantação automatizada como Capistrano de Ruby, mas mais simples e claro para Python. Ele foi construido em cima de paramiko.
Você não pode querer fazer 'implantação automatizada', mas Fabric se adequar ao seu caso de uso perfeitamente no entanto. Para mostrar como é simples Tecido é: o arquivo fab e comando para o seu script ficaria assim (não testado, mas 99% de certeza que ele vai trabalhar):
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
Em seguida, execute o arquivo com o comando fab:
fab -f fab_putfile.py put_file:file=./path/to/my/file
E pronto! :)
Aqui está um exemplo usando pysftp e uma chave privada.
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 é um fácil de usar sftp módulo que utiliza paramiko e PyCrypto. Ele fornece uma interface simples para sftp .. Outras coisas que você pode fazer com pysftp que são bastante úteis:
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
Mais comandos e sobre PySFTP aqui .
torcida pode ajudá-lo com o que você está fazendo, consulte a sua documentação, há uma abundância de exemplos . Também é um produto maduro com uma grande comunidade de desenvolvedores / usuário por trás dele.
Você pode usar o pexpect módulo
Aqui está uma boa introdução pós
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')
Eu não testei isso, mas ele deve funcionar
paramiko é tão lento. Use subprocess e da casca, aqui está um exemplo:
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)
Com o RSA Key seguida, consulte aqui
trechos:
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)
Há um monte de respostas que mencionam pysftp, assim, no evento que você quer um invólucro gerente de contexto em torno pysftp, aqui é uma solução que é ainda menos código que acaba parecendo o seguinte quando usado
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.")
A (mais completa) Exemplo: http: / /www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html
Este gerente contexto passa a ter uma lógica auto-repetição cozido em no caso de você não pode se conectar pela primeira vez ao redor (que surpreendentemente acontece com mais freqüência do que você esperaria em um ambiente de produção ...)
O gerente essência contexto para open_sftp
: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515