it-swarm-id.com

Bagaimana cara menyalin file ke server jauh di Python menggunakan SCP atau SSH?

Saya memiliki file teks pada mesin lokal saya yang dihasilkan oleh skrip Python harian yang dijalankan di cron. 

Saya ingin menambahkan sedikit kode agar file itu dikirim dengan aman ke server saya melalui SSH.

85
Alok

Jika Anda menginginkan pendekatan sederhana, ini harus berhasil.

Anda akan ingin ".close ()" file terlebih dahulu sehingga Anda tahu itu memerah ke disk dari Python.

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

Anda perlu membuat (pada mesin sumber) dan menginstal (pada mesin tujuan) terlebih dahulu kunci ssh sehingga scp secara otomatis diautentikasi dengan kunci ssh publik Anda (dengan kata lain, sehingga skrip Anda tidak meminta kata sandi) . 

contoh ssh-keygen

39
pdq

Untuk melakukan ini dengan Python (mis. Tidak membungkus scp melalui subprocess.Popen atau serupa) dengan perpustakaan Paramiko , Anda akan melakukan sesuatu seperti ini:

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

(Anda mungkin ingin berurusan dengan host yang tidak dikenal, kesalahan, membuat direktori yang diperlukan, dan sebagainya).

129
Tony Meyer

Anda mungkin akan menggunakan modul subprocess . Sesuatu seperti ini:

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

Di mana destination mungkin berbentuk [email protected]:remotepath. Terima kasih kepada @ Charles Duffy untuk menunjukkan kelemahan dalam jawaban asli saya, yang menggunakan argumen string tunggal untuk menentukan operasi scp Shell=True - yang tidak akan menangani spasi putih di jalur.

Dokumentasi modul memiliki contoh pemeriksaan kesalahan yang mungkin ingin Anda lakukan sehubungan dengan operasi ini.

Pastikan Anda telah mengatur kredensial yang tepat sehingga Anda dapat melakukan tanpa pengawasan, tanpa kata sandi scp di antara mesin . Ada stackoverflow pertanyaan untuk ini sudah .

28
Blair Conrad

Ada beberapa cara berbeda untuk mendekati masalah:

  1. Bungkus program baris perintah
  2. menggunakan pustaka Python yang menyediakan kemampuan SSH (misalnya - Paramiko atau Twisted Conch )

Setiap pendekatan memiliki kebiasaan sendiri. Anda perlu mengatur kunci SSH untuk mengaktifkan login tanpa kata sandi jika Anda membungkus perintah sistem seperti "ssh", "scp" atau "rsync." Anda dapat menyematkan kata sandi dalam skrip menggunakan Paramiko atau perpustakaan lain, tetapi Anda mungkin menemukan kurangnya dokumentasi yang membuat frustrasi, terutama jika Anda tidak terbiasa dengan dasar-dasar koneksi SSH (mis. - pertukaran kunci, agen, dll). Mungkin tidak perlu dikatakan bahwa kunci SSH hampir selalu merupakan ide yang lebih baik daripada kata sandi untuk hal-hal semacam ini.

CATATAN: sulit untuk mengalahkan rsync jika Anda berencana mentransfer file melalui SSH, terutama jika alternatifnya scp tua biasa.

Saya telah menggunakan Paramiko dengan mata untuk mengganti panggilan sistem tetapi menemukan diri saya tertarik kembali ke perintah yang dibungkus karena kemudahan penggunaan dan keakraban langsung. Anda mungkin berbeda. Saya memberi Conch beberapa kali yang lalu, tetapi itu tidak menarik bagi saya.

Jika memilih jalur system-call, Python menawarkan berbagai opsi seperti os.system atau modul perintah/subproses. Saya akan menggunakan modul subproses jika menggunakan versi 2.4+.

10
Michael

Mencapai masalah yang sama, tetapi bukannya "meretas" atau meniru baris perintah:

Ditemukan jawaban ini di sini .

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

Anda dapat menggunakan paket pengikut, yang persis dirancang untuk ini.

Yang Anda butuhkan hanyalah menginstal pengikut dan lakukan

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

Juga, itu akan menghemat autentikasi kredensial Anda dan tidak perlu mengetiknya lagi dan lagi.

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

pendekatan yang sangat sederhana adalah sebagai berikut: 

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

tidak diperlukan pustaka python (hanya os) dan itu berfungsi

0

Coba ini jika Anda tidak ingin menggunakan sertifikat 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
JavDomGom

Saya menggunakan sshfs untuk memasang direktori remote melalui ssh, dan shutil untuk menyalin file:

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

Kemudian dengan python:

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

Metode ini memiliki keuntungan bahwa Anda dapat mengalirkan data jika Anda menghasilkan data daripada melakukan caching secara lokal dan mengirim satu file besar.

0
Jonno_FTW

Memanggil perintah scp melalui subproses tidak memungkinkan untuk menerima laporan kemajuan di dalam skrip. pexpect dapat digunakan untuk mengekstrak info itu:

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

Lihat salin file python di jaringan lokal (linux -> linux)

0
jfs