SFTP в Python? (независимая платформа)

181

Я работаю над простым инструментом, который передает файлы в жестко запрограммированном месте с паролем также жестко. Я новичок в Python, но благодаря ftplib это было легко:

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)

Проблема в том, что я не могу найти библиотеку, которая поддерживает sFTP. Какой нормальный способ сделать что-то подобное безопасно?

Изменить: Благодаря ответам здесь, я получил его работать с Paramiko, и это был синтаксис.

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

Еще раз спасибо!

Марк Уилбур
источник
1
Спасибо ! Получил скрипт загрузки SFTP, работающий за 5 минут :)
Ohad Schneider
1
Просто общее замечание по первоначальному вопросу, что python ftplib также поддерживает FTPS - ftp over TLS en.m.wikipedia.org/wiki/FTPS . Серверы FTPS возможно менее используются в мире Unix, отчасти из-за вездесущности ssh / sftp, однако серверы sftp гораздо реже присутствуют в среде Windows, где FTPS более распространен.
Гнудифф
Похоже, поддержка FTPS была добавлена ​​в Python 3.2 с расширенным источником класса : class ftplib.FTP_TLS (host = '', user = '', passwd = '', acct = '', keyfile = None, certfile = None, context = Нет, тайм-аут = Нет, source_address = Нет)
mgrollins

Ответы:

109

Paramiko поддерживает SFTP. Я использовал это, и я использовал Twisted. Оба имеют свое место, но вам может быть легче начать с Paramiko.

Брайан Клаппер
источник
2
Да, Paramiko - это путь, который очень удобен в использовании, немного сложно найти пакет pycrypto для windows, который является зависимостью.
Маули
Спасибо. Мне потребовалось некоторое время, чтобы понять, как установить пакет из-за отсутствия инструкций по установке в файле readme, но это было именно то, что мне было нужно!
Марк Уилбур
15
См. Bitprophet.org/blog/2012/09/29/paramiko-and-ssh, в котором Джефф Форсье объясняет, что ssh устарел, а paramiko - путь вперед.
Кристофер Махан
2
Также есть code.google.com/p/pysftp, основанный на Paramiko, но более простой в использовании
franzlorenzon
78

Вы должны проверить pysftp https://pypi.python.org/pypi/pysftp, это зависит от paramiko, но в большинстве случаев используется только несколько строк кода.

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в примере
Роман Подлинов
2
pip install pysftp
Боб Стейн
2
Есть ли возможность автоматически добавлять новый хост sftp к известным хостам?
user443854
1
@ user443854 да, есть pysftp.readthedocs.io/en/release_0.2.9/… Но я бы определенно не рекомендовал этого, хотя вы можете добавить еще один файл
known_host
15

Если вы хотите легко и просто, вы также можете посмотреть на ткани . Это инструмент автоматического развертывания, подобный Ruby Capistrano, но более простой и, конечно, для Python. Он построен на вершине Парамико.

Возможно, вы не захотите делать «автоматическое развертывание», но Fabric идеально подойдет для вашего случая использования. Чтобы показать вам, насколько простой Fabric: fab-файл и команда для вашего скрипта будут выглядеть так (не проверено, но на 99% уверены, что это будет работать):

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

Затем запустите файл с помощью команды fab:

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

И вы сделали! :)

hopla
источник
12

Вот пример использования pysftp и закрытого ключа.

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 - это простой в использовании модуль sftp, который использует paramiko и pycrypto. Он предоставляет простой интерфейс для sftp. Другие вещи, которые вы можете сделать с pysftp, которые весьма полезны:

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

Больше команд и про PySFTP здесь .

radtek
источник
srv.get(file_path) # Download a file from remote serverВы можете объяснить, куда он загружает файл?
Маркус Месканен
Вы пробовали местный для вас казнены от?
Радтек
Да, но где в файловой системе? Все проходит успешно, но я не могу найти файл нигде.
Маркус Месканен,
Извините, я имел в виду местный реж. Попробуйте выполнить скрипт из вашего домашнего каталога и посмотреть, есть ли файл там.
Радтек
3

Twisted может помочь вам с тем, что вы делаете, ознакомьтесь с их документацией, есть множество примеров. Также это зрелый продукт, за которым стоит большое сообщество разработчиков и пользователей.

Сергей Головченко
источник
1

С ключом RSA тогда обратитесь сюда

Отрывок:

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
источник
0

Существует множество ответов, в которых упоминается pysftp, поэтому в случае, если вам нужна обертка менеджера контекста вокруг pysftp, вот решение, которое еще меньше кода и в конечном итоге выглядит как следующий

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

(Более полный) пример: http://www.prschmid.com/2016/09/simple-opensftp-context-manager-for.html

Этот контекстный менеджер имеет встроенную логику автоматического повтора, если вы не можете подключиться в первый раз (что на удивление происходит чаще, чем вы ожидаете в производственной среде ...)

Суть контекстного менеджера для open_sftp: https://gist.github.com/prschmid/80a19c22012e42d4d6e791c1e4eb8515

prschmid
источник
0

Парамико так медленно. Используйте подпроцесс и оболочку, вот пример:

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)
杨 李思
источник
Речь идет о «Python», который обычно подразумевает придерживаться этого - особенно, когда есть так много вариантов для этого. Что еще более важно, он говорит «Платформа независима». Я не могу сказать, работает ли ваш ответ быстрее или нет. Может быть?
BuvinJ
0

PyFilesystem с ее sshfs является одним из вариантов. Он использует Paramiko под капотом и обеспечивает более приятный независимый интерфейс.

import fs

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

или

from fs.sshfs import SSHFS
sf = SSHFS(...
fmalina
источник
-1

Вы можете использовать модуль pexpect

Вот хороший вступительный пост

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

Я не проверял это, но это должно работать

Mikee
источник