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

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

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

Ответ 1

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

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

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

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

пример ssh-keygen

Ответ 2

Чтобы сделать это в Python (т.е. не обертывать scp через subprocess.Popen или подобное) с помощью библиотеки Paramiko, вы бы сделали что-то например:

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

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

Ответ 3

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

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

Где destination, вероятно, имеет вид [email protected]:remotepath. Благодаря @Charles Duffy за то, что он указал на слабость моего первоначального ответа, который использовал один строковый аргумент для указания операции scp shell=True, которая не обрабатывала бы пробелы в путях.

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

Убедитесь, что вы установили правильные учетные данные, чтобы вы могли выполнять автоматическую, без пароля scp между машинами. Для этого уже существует вопрос fooobar.com/questions/28840/....

Ответ 4

Существует несколько способов решения этой проблемы:

  • Запустить программы командной строки
  • используйте библиотеку Python, которая предоставляет возможности SSH (например, Paramiko или Twisted Conch)

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

ПРИМЕЧАНИЕ: его трудно побить rsync, если вы планируете передавать файлы через SSH, особенно если альтернатива - это простой старый scp.

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

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

Ответ 5

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

Нашел этот ответ здесь.

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

Ответ 6

Вы можете сделать что-то вроде этого, чтобы обработать проверку ключа хоста, а также

import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path [email protected]:remote_path")

Ответ 7

fabric можно использовать для загрузки файлов в 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()

Ответ 8

Вы можете использовать пакет vassal, который специально предназначен для этого.

Все, что вам нужно, это установить вассал и сделать

from vassal.terminal import Terminal
shell = Terminal(["scp [email protected]:/home/foo.txt foo_local.txt"])
shell.run()

Кроме того, он сохранит вашу аутентификацию учетных данных и не нужно будет вводить их снова и снова.

Ответ 9

Вызов команды scp через подпроцесс не позволяет получать отчет о ходе работы внутри script. 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)

Ответ 10

Использование внешнего ресурса paramiko;

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

Ответ 11

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

import os
os.system('sshpass -p "password" scp [email protected]:/path/to/file ./')

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

Ответ 12

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

$ mkdir ~/sshmount
$ sshfs [email protected]:/path/to/remote/dst ~/sshmount

Затем в python:

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

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

Ответ 13

Попробуйте это, если вы не будете использовать SSL-сертификаты:

import subprocess

try:
    # Set scp and ssh data.
    connUser = 'john'
    connHost = 'my.host.com'
    connPath = '/home/john/'
    connPrivateKey = '/home/user/myKey.pem'

    # Use scp to send file from local to host.
    scp = subprocess.Popen(['scp', '-i', connPrivateKey, 'myFile.txt', '{}@{}:{}'.format(connUser, connHost, connPath)])

except CalledProcessError:
    print('ERROR: Connection to host failed!')

Ответ 14

Вид хаки, но следующее должно работать:)

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