Как скопировать файл на удаленный сервер в Python, используя SCP или SSH? - PullRequest
90 голосов
/ 16 сентября 2008

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

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

Ответы [ 13 ]

134 голосов
/ 16 сентября 2008

Чтобы сделать это в 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()

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

45 голосов
/ 16 сентября 2008

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

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

import os
os.system("scp FILE USER@SERVER:PATH")
#e.g. os.system("scp foo.bar joe@srvr.net:/path/to/foo.bar")

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

Пример ssh-keygen

29 голосов
/ 16 сентября 2008

Вы, вероятно, используете модуль подпроцесса . Примерно так:

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

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

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

Убедитесь, что вы установили правильные учетные данные, чтобы вы могли выполнять автоматическую scp без пароля между компьютерами . Для этого вопроса уже есть stackoverflow .

11 голосов
/ 16 сентября 2008

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

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

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

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

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

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

6 голосов
/ 24 июля 2016

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

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

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')
3 голосов
/ 28 марта 2014

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()
1 голос
/ 16 ноября 2018

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

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

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

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

0 голосов
/ 27 ноября 2018

Попробуйте, если вы не хотите использовать 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!')
0 голосов
/ 06 февраля 2018

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

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

Тогда в python:

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

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

0 голосов
/ 04 января 2018

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

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

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

...