Jak skopiować plik Na zdalny serwer w Pythonie za pomocą SCP lub SSH?

Mam plik tekstowy na mojej lokalnej maszynie, który jest generowany przez codzienny skrypt Pythona uruchamiany w cron.

Chciałbym dodać trochę kodu, aby ten plik został bezpiecznie wysłany na mój serwer przez SSH.

Author: ayhan, 2008-09-16

11 answers

Jeśli chcesz prostego podejścia, to powinno zadziałać.

Będziesz chciał ".close()" najpierw plik, aby wiedzieć, że jest spłukany na dysk z Pythona.

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

Musisz wygenerować (na maszynie źródłowej) i zainstalować (na maszynie docelowej) klucz ssh, aby scp automatycznie został uwierzytelniony Twoim publicznym kluczem ssh (innymi słowy, aby skrypt nie pytał o hasło).

Przykład Ssh-keygen

 36
Author: pdq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 01:01:43

Aby to zrobić w Pythonie (tzn. nie zawijać scp przez podproces.Popen lub podobne) z biblioteką Paramiko , zrobiłbyś coś takiego:

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

(prawdopodobnie chciałbyś poradzić sobie z nieznanymi hostami, błędami, tworzeniem wszelkich niezbędnych katalogów i tak dalej).

 124
Author: Tony Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-08 09:03:19

Prawdopodobnie użyłbyś modułu podprocesowego . Coś takiego:

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

Gdzie {[1] } jest prawdopodobnie formą user@remotehost:remotepath. Dzięki @ Charles Duffy za zwrócenie uwagi na słabość mojej oryginalnej odpowiedzi, która użyła pojedynczego argumentu łańcuchowego do określenia operacji scp shell=True - która nie radzi sobie z białymi spacjami w ścieżkach.

Dokumentacja modułu zawiera przykłady sprawdzania błędów, które można wykonać w połączeniu z tą operacją.

Zapewnić że ustawiłeś odpowiednie poświadczenia, abyś mógł wykonać bez nadzoru, bez hasła scp pomiędzy maszynami . Istnieje już pytanie o stackoverflow.

 28
Author: Blair Conrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:32

Istnieje kilka różnych sposobów podejścia do problemu:

  1. Zawijanie programów wiersza poleceń
  2. Użyj Biblioteki Pythona, która udostępnia możliwości SSH (np. - Paramiko lub Twisted Conch )

Każde podejście ma swoje dziwactwa. Musisz skonfigurować klawisze SSH, aby włączyć logowanie bez hasła, jeśli owijasz Polecenia systemowe ,takie jak" ssh"," scp "lub" rsync."Możesz osadzić hasło w skrypcie za pomocą Paramiko lub innej biblioteki, ale możesz znajdź brak dokumentacji frustrujące, zwłaszcza jeśli nie są zaznajomieni z podstawami połączenia SSH (np-wymiany kluczy, agentów, itp). Prawdopodobnie jest oczywiste, że klucze SSH są prawie zawsze lepszym pomysłem niż hasła do tego rodzaju rzeczy.

Notatka: trudno jest pokonać rsync, jeśli planujesz przesyłać pliki przez SSH, zwłaszcza jeśli alternatywą jest zwykły stary scp.

Używałem Paramiko z zamiarem zastąpienia wywołań systemowych, ale znalazłem się narysowany powrót do poleceń owiniętych ze względu na ich łatwość obsługi i natychmiastową znajomość. Możesz być inna. Dałem Conch raz-over jakiś czas temu, ale to nie przypadło mi do gustu.

Jeśli wybierzesz ścieżkę wywołania systemowego, Python oferuje szereg opcji, takich jak system operacyjny.system lub Moduły poleceń/podprocesów. Wybrałbym moduł podprocesowy, Jeśli używam wersji 2.4+.

 10
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 01:32:08

Wystąpił ten sam problem, ale zamiast "hakowania" lub emulowania linii poleceń:

Znalazłem tę odpowiedź tutaj .

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')
 5
Author: Maviles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-16 12:04:43

fabric może być używany do przesyłania plików 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()
 3
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-03 19:46:04

Wywołanie polecenia scp przez podproces nie pozwala na otrzymywanie raportu postępu wewnątrz skryptu. pexpect może być użyty do wyodrębnienia tej informacji:

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

Zobacz plik kopiowania Pythona w sieci lokalnej (linux -> linux)

 0
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:59
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')
 0
Author: michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-12 01:51:37

Bardzo proste podejście jest następujące:

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

Żadna biblioteka Pythona nie jest wymagana (tylko os) i działa

 0
Author: Roberto Marzocchi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-04 15:40:07

Użyłem sshfs do zamontowania zdalnego katalogu przez ssh, a shutil do skopiowania plików:

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

Następnie w Pythonie:

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

Ta metoda ma tę zaletę, że możesz przesyłać strumieniowo dane, jeśli generujesz dane, a nie buforujesz lokalnie i wysyłasz jeden duży plik.

 0
Author: Jonno_FTW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 02:58:25

Trochę hacky, ale to powinno zadziałać:)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" [email protected]:"+serverPath)
 -2
Author: Drew Olson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 00:56:31