У меня есть текстовый файл на моей локальной машине, который генерируется ежедневным запуском Python script в cron.
Я хотел бы добавить немного кода, чтобы этот файл был надежно отправлен на мой сервер через SSH.
У меня есть текстовый файл на моей локальной машине, который генерируется ежедневным запуском Python script в cron.
Я хотел бы добавить немного кода, чтобы этот файл был надежно отправлен на мой сервер через SSH.
Если вам нужен простой подход, это должно сработать.
Сначала вы захотите ".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 не попросите пароль).
Чтобы сделать это в 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()
(Возможно, вам захочется иметь дело с неизвестными хостами, ошибками, создавать любые необходимые каталоги и т.д.).
Вероятно, вы используете модуль подпроцесса . Что-то вроде этого:
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/....
Существует несколько способов решения этой проблемы:
Каждый подход имеет свои собственные причуды. Вам нужно будет настроить SSH-ключи, чтобы включить учетные записи без пароля, если вы обмениваете системные команды, такие как "ssh", "scp" или "rsync". Вы можете вставлять пароль в script с помощью Paramiko или какой-либо другой библиотеки, но вы можете обнаружить, что недостаток документации разочаровывает, особенно если вы не знакомы с основами SSH-соединения (например, обмен ключами, агенты и т.д.), Возможно, само собой разумеется, что ключи SSH почти всегда лучше, чем пароли для такого рода вещей.
ПРИМЕЧАНИЕ: его трудно побить rsync, если вы планируете передавать файлы через SSH, особенно если альтернатива - это простой старый scp.
Я использовал Paramiko с целью замены системных вызовов, но обнаружил, что обратился к завернутым командам из-за их простоты использования и непосредственного знакомства. Вы можете быть разными. Некоторое время назад я дал Кончу, но он не понравился мне.
Если вы выбираете путь системного вызова, Python предлагает массив таких параметров, как os.system или команды/подпроцессы. Я бы пошел с модулем подпроцесса при использовании версии 2.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')
Вы можете сделать что-то вроде этого, чтобы обработать проверку ключа хоста, а также
import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path [email protected]:remote_path")
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()
Вы можете использовать пакет vassal, который специально предназначен для этого.
Все, что вам нужно, это установить вассал и сделать
from vassal.terminal import Terminal
shell = Terminal(["scp [email protected]:/home/foo.txt foo_local.txt"])
shell.run()
Кроме того, он сохранит вашу аутентификацию учетных данных и не нужно будет вводить их снова и снова.
Вызов команды 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})
Использование внешнего ресурса 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')
очень простой подход заключается в следующем:
import os
os.system('sshpass -p "password" scp [email protected]:/path/to/file ./')
библиотека python не требуется (только os), и она работает
Я использовал sshfs для монтирования удаленного каталога через ssh и shutil для копирования файлов:
$ mkdir ~/sshmount
$ sshfs [email protected]:/path/to/remote/dst ~/sshmount
Затем в python:
import shutil
shutil.copy('a.txt', '~/sshmount')
Этот метод имеет то преимущество, что вы можете передавать данные, если вы генерируете данные, а не кешируете локально и отправляете один большой файл.
Попробуйте это, если вы не будете использовать 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!')
Вид хаки, но следующее должно работать:)
import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" [email protected]:"+serverPath)