Domanda

Ho un file di testo sul mio computer locale generato da uno script Python quotidiano eseguito in cron.

Vorrei aggiungere un po' di codice per inviare il file in modo sicuro al mio server tramite SSH.

È stato utile?

Soluzione

Se vuoi l'approccio semplice, questo dovrebbe funzionare.

Ti consigliamo di ".close()" prima il file in modo da sapere che è stato scaricato su disco da Python.

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

È necessario generare (sul computer di origine) e installare (sul computer di destinazione) una chiave ssh in anticipo in modo che scp venga automaticamente autenticato con la chiave ssh pubblica (in altre parole, quindi lo script non richiede una password) .

esempio di ssh-keygen

Altri suggerimenti

Per farlo in Python (es.non avvolgendo scp tramite subprocess.Popen o simili) con il file Paramiko libreria, faresti qualcosa del genere:

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

(Probabilmente vorrai occuparti di host sconosciuti, errori, creazione di directory necessarie e così via).

Probabilmente utilizzeresti il modulo del sottoprocesso.Qualcosa come questo:

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

Dove destination è probabilmente della forma user@remotehost:remotepath.Grazie a @charles Duffy per aver sottolineato la debolezza nella mia risposta originale, che ha utilizzato un argomento a stringa singolo per specificare l'operazione SCP shell=True - questo non gestirebbe gli spazi bianchi nei percorsi.

La documentazione del modulo ha esempi di controllo degli errori che potresti voler eseguire insieme a questa operazione.

Assicurati di aver impostato le credenziali corrette in modo da poter eseguire un'operazione SCP incustodito e senza password tra le macchine.C'è un domanda stackoverflow già per questo.

Esistono un paio di modi diversi per affrontare il problema:

  1. Avvolgere i programmi da riga di comando
  2. utilizzare una libreria Python che fornisce funzionalità SSH (ad esempio - Paramiko O Conchiglia contorta)

Ogni approccio ha le sue peculiarità.Dovrai impostare i tasti SSH per abilitare gli accessi senza password se si sta avvolgendo comandi di sistema come "SSH", "SCP" o "RSYNC". Puoi incorporare una password in uno script usando Paramiko o qualche altra libreria, ma potresti trovare la mancanza di documentazione frustrante, specialmente se non hai familiarità con le basi della connessione SSH (ad es. Scambi chiave, agenti, ecc.).Probabilmente è ovvio che le chiavi SSH sono quasi sempre un'idea migliore delle password per questo genere di cose.

NOTA:è difficile battere rsync se prevedi di trasferire file tramite SSH, soprattutto se l'alternativa è il vecchio scp.

Ho usato Paramiko con l'obiettivo di sostituire le chiamate di sistema, ma mi sono ritrovato attratto dai comandi racchiusi a causa della loro facilità d'uso e familiarità immediata.Potresti essere diverso.Ho dato un'occhiata a Conch qualche tempo fa ma non mi ha attirato.

Se si opta per il percorso della chiamata di sistema, Python offre una serie di opzioni come os.system o i moduli comandi/sottoprocesso.Sceglierei il modulo subprocess se si utilizza la versione 2.4+.

Raggiunto lo stesso problema, ma invece di "hacking" o emulare la riga di comando:

Ho trovato questa risposta Qui.

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

fabric potrebbe essere usato per caricare file tramite 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()

Puoi usare il pacchetto vassal, che è progettato esattamente per questo.

Tutto ciò che serve è installare Vassal e farlo

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

Inoltre, ti farà risparmiare le credenziali di autenticazione e non sarà necessario digitarle ancora e ancora.

Chiamando scp il comando tramite sottoprocesso non consente di ricevere il rapporto sullo stato di avanzamento all'interno dello script. pexpect potrebbe essere usato per estrarre tali informazioni:

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

Vedere copia del file python nella rete locale (linux -> linux)

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

ero solito sshfs per montare la directory remota tramite ssh e chiuso per copiare i file:

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

Quindi in Python:

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

Questo metodo ha il vantaggio di poter eseguire lo streaming dei dati se si stanno generando dati anziché memorizzarli nella cache locale e inviare un singolo file di grandi dimensioni.

Prova questo se non desideri utilizzare i certificati 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!')

un approccio molto semplice è il seguente:

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

non è richiesta alcuna libreria Python (solo sistema operativo) e funziona

Un po' complicato, ma quanto segue dovrebbe funzionare :)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top