Как скопировать файл на удаленный сервер в Python с помощью SCP или SSH?



У меня есть текстовый файл на моем локальном компьютере, который генерируется ежедневным скриптом Python, запущенным в cron.



Я хотел бы добавить немного кода, чтобы этот файл был безопасно отправлен на мой сервер через SSH.

820   11  

11 ответов:

Если вы хотите простой подход, это должно работать.

вы хотите ".закройте () " сначала файл, чтобы вы знали, что он сброшен на диск С Python.

import os
os.system("scp FILE USER@SERVER:PATH")
#e.g. os.system("scp foo.bar [email protected]:/path/to/foo.bar")

вам нужно сгенерировать (на исходной машине) и установить (на целевой машине) ssh-ключ заранее, чтобы scp автоматически аутентифицировался с помощью вашего открытого ssh-ключа (другими словами, чтобы ваш скрипт не запрашивал пароль).

ssh-keygen пример

чтобы сделать это в Python (т. е. не обертывать scp через подпроцесс.Попен или подобное) с Парамико библиотека, вы бы сделали что-то вроде этого:

import os
import paramiko

ssh = paramiko.SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username=username, password=password)
sftp = ssh.open_sftp()
sftp.put(localpath, remotepath)
sftp.close()
ssh.close()

(вероятно, вы захотите иметь дело с неизвестными хостами, ошибками, созданием любых необходимых каталогов и т. д.).

вы, вероятно, использовать модуль подпроцесс. Что-то вроде этого:

import subprocess
p = subprocess.Popen(["scp", myfile, destination])
sts = os.waitpid(p.pid, 0)

здесь destination вероятно, имеет вид user@remotehost:remotepath. Благодаря @Charles Duffy за указание на слабость в моем исходном ответе, который использовал один строковый аргумент для указания операции scp shell=True - это не будет обрабатывать пробелы в пути.

документация модуля имеет примеры ошибок, которые вы можете выполнять в сочетании с этим операция.

убедитесь, что вы настроили правильные учетные данные, чтобы вы могли выполнить без присмотра, беспарольный УПП между машинами. Там есть stackoverflow вопрос для этого уже.

есть несколько различных способов подойти к проблеме:

  1. обернуть программы командной строки
  2. используйте библиотеку Python, которая предоставляет возможности SSH (например -Парамико или Витой Рог)

каждый подход имеет свои тонкости. Вам нужно будет настроить ключи SSH для включения входа без пароля, если вы обертываете системные команды, такие как "ssh", "scp" или "rsync."Вы можете встроить пароль в скрипт с помощью Paramiko или какой - то другой библиотеки, но вы можете найти отсутствие документации расстраивает, особенно если вы не знакомы с основами соединения SSH (например, обмен ключами, агенты и т.д.). Это, вероятно, само собой разумеется, что SSH-ключи, почти всегда лучше, чем пароли для такого рода вещи.

Примечание: его трудно превзойти rsync, если вы планируете передавать файлы через SSH, особенно если альтернативой является простой старый scp.

Я использовал Paramiko с глазом в сторону замена системных вызовов, но обнаружил, что меня тянет обратно к обернутым командам из-за их простоты использования и непосредственного знакомства. Ты можешь быть другим. Некоторое время назад я осмотрел Конча, но мне это не понравилось.

при выборе пути системного вызова Python предлагает множество опций, таких как ОС.система или модули команд / подпроцессов. Я бы пошел с модулем подпроцесса при использовании версией 2.4+.

достиг той же проблемы, но вместо "взлома" или эмуляции командной строки:

нашли этот ответ!--4-->здесь.

from paramiko import SSHClient
from scp import SCPClient

ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('example.com')

with SCPClient(ssh.get_transport()) as scp:
    scp.put('test.txt', 'test2.txt')
    scp.get('test2.txt')

fabric может использоваться для загрузки файлов vis ssh:

#!/usr/bin/env python
from fabric.api import execute, put
from fabric.network import disconnect_all

if __name__=="__main__":
    import sys
    # specify hostname to connect to and the remote/local paths
    srcdir, remote_dirname, hostname = sys.argv[1:]
    try:
        s = execute(put, srcdir, remote_dirname, host=hostname)
        print(repr(s))
    finally:
        disconnect_all()

вызов scp команда через подпроцесс не позволяет получить отчет о ходе выполнения внутри скрипта. pexpect может быть использован для извлечения этой информации:

import pipes
import re
import pexpect # $ pip install pexpect

def progress(locals):
    # extract percents
    print(int(re.search(br'(\d+)%$', locals['child'].after).group(1)))

command = "scp %s %s" % tuple(map(pipes.quote, [srcfile, destination]))
pexpect.run(command, events={r'\d+%': progress})

посмотреть python копировать файл в локальной сети (linux -> linux)

from paramiko import SSHClient
from scp import SCPClient
import os

ssh = SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username='username', password='password')
with SCPClient(ssh.get_transport()) as scp:
        scp.put('test.txt', 'test2.txt')

очень простой подход заключается в следующем:

import os
sshpass -p "password" scp user@host:/path/to/file ./

библиотека python не требуется (только ОС), и она работает

Я sshfs для подключения удаленного каталога через ssh, и shutil скопировать файлы:

$ mkdir ~/sshmount
$ sshfs user@remotehost:/path/to/remote/dst ~/sshmount

затем в python:

import shutil
shutil.copy('a.txt', '~/sshmount')

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

вроде hacky, но следующее должно работать :)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" [email protected]:"+serverPath)

Comments

    Ничего не найдено.