it-swarm-eu.dev

Wie kopiere ich eine Datei mit SCP oder SSH auf einen Remote-Server in Python?

Ich habe eine Textdatei auf meinem lokalen Rechner, die von einem täglichen Python-Skript generiert wird, das in cron ausgeführt wird. 

Ich möchte ein wenig Code hinzufügen, damit diese Datei sicher über SSH an meinen Server gesendet wird.

85
Alok

Wenn Sie den einfachen Ansatz wünschen, sollte dies funktionieren.

Sie müssen zuerst die Datei ".close ()" wählen, damit Sie wissen, dass sie von Python auf die Festplatte geschrieben wird.

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

Sie müssen (auf dem Quellcomputer) einen SSH-Schlüssel generieren und installieren (auf dem Zielcomputer), damit der SCP automatisch mit Ihrem öffentlichen SSH-Schlüssel authentifiziert wird (mit anderen Worten, Ihr Skript fragt nicht nach einem Kennwort). . 

ssh-keygen Beispiel

39
pdq

Um dies in Python (d. H. SCP nicht durch Subprozess.Popen oder ähnliches umzuwickeln) mit der Bibliothek " Paramiko " auszuführen, würden Sie Folgendes tun:

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

(Möglicherweise möchten Sie sich mit unbekannten Hosts, Fehlern befassen, alle erforderlichen Verzeichnisse erstellen usw.).

129
Tony Meyer

Sie würden wahrscheinlich das Modul Subprozess verwenden. Etwas wie das:

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

Wobei destination wahrscheinlich die Form [email protected]:remotepath hat. Vielen Dank an @ Charles Duffy für den Hinweis auf die Schwachstelle in meiner ursprünglichen Antwort, die ein einzelnes String-Argument verwendet hat, um die SCP-Operation Shell=True anzugeben.

Die Dokumentation des Moduls enthält Beispiele für Fehlerprüfungen, die Sie möglicherweise in Verbindung mit dieser Operation durchführen möchten.

Stellen Sie sicher, dass Sie die richtigen Anmeldeinformationen eingerichtet haben, um einen unbeaufsichtigten, kennwortlosen SCP zwischen den Maschinen durchführen zu können . Es gibt bereits eine stackoverflow-Frage .

28
Blair Conrad

Es gibt verschiedene Möglichkeiten, das Problem anzugehen:

  1. Befehlszeilenprogramme umbrechen
  2. eine Python-Bibliothek verwenden, die SSH-Funktionen bietet (z. B. - Paramiko oder Twisted Conch )

Jeder Ansatz hat seine eigenen Macken. Sie müssen SSH-Schlüssel einrichten, um kennwortlose Anmeldungen zu aktivieren, wenn Sie Systembefehle wie "ssh", "scp" oder "rsync" umschließen. Sie können ein Kennwort mit Hilfe von Paramiko oder einer anderen Bibliothek in ein Skript einbetten. Die fehlende Dokumentation kann jedoch frustrierend sein, insbesondere wenn Sie mit den Grundlagen der SSH-Verbindung nicht vertraut sind (z. B. Schlüsselaustausch, Agenten usw.). Es ist wahrscheinlich selbstverständlich, dass SSH-Schlüssel fast immer eine bessere Idee sind als Passwörter für diese Art von Sachen.

HINWEIS: Rsync ist schwer zu übertreffen, wenn Sie die Übertragung von Dateien über SSH planen. Dies gilt insbesondere, wenn die Alternative normaler scp ist.

Ich habe Paramiko im Hinblick auf das Ersetzen von Systemaufrufen verwendet, fand mich aber aufgrund der Benutzerfreundlichkeit und der unmittelbaren Vertrautheit mit den umschlossenen Befehlen verbunden. Du könntest anders sein. Ich habe Conch vor einiger Zeit einmal gegeben, aber es hat mir nicht gefallen.

Wenn Sie sich für den Systemaufrufpfad entscheiden, bietet Python eine Reihe von Optionen wie os.system oder die Befehle/Unterprozessmodule. Ich würde mit dem Subprozess-Modul gehen, wenn Sie Version 2.4 oder höher verwenden.

10
Michael

Das gleiche Problem wurde erreicht, aber anstatt "zu hacken" oder die Befehlszeile zu emulieren:

Diese Antwort gefunden hier .

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
Maviles

Sie können so etwas tun, um auch die Überprüfung des Host-Schlüssels durchzuführen

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

fabric kann verwendet werden, um Dateien über ssh hochzuladen:

#!/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
jfs

Sie können das Vasall-Paket verwenden, das genau dafür entwickelt wurde.

Alles was Sie brauchen ist, Vasall zu installieren und zu tun

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

Außerdem werden Sie Ihre Anmeldeinformationen speichern und müssen sie nicht immer wieder eingeben.

1
Shawn
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
michael

ein sehr einfacher Ansatz ist der folgende: 

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

es wird keine Python-Bibliothek benötigt (nur os) und es funktioniert

0

Versuchen Sie dies, wenn Sie SSL-Zertifikate verwenden möchten:

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
JavDomGom

Ich habe sshfs verwendet, um das Remote-Verzeichnis über ssh einzuhängen, und shutil , um die Dateien zu kopieren:

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

Dann in Python:

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

Diese Methode hat den Vorteil, dass Sie Daten streamen können, wenn Sie Daten generieren, anstatt lokal zu cachen und eine einzige große Datei zu senden.

0
Jonno_FTW

Wenn Sie den Befehl scp über einen Unterprozess aufrufen, kann der Fortschrittsbericht nicht im Skript empfangen werden. pexpect könnte verwendet werden, um diese Informationen zu extrahieren:

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

Siehe Python-Kopierdatei im lokalen Netzwerk (linux -> linux)

0
jfs