it-swarm-vi.tech

Làm cách nào để sao chép tệp vào máy chủ từ xa bằng Python bằng SCP hoặc SSH?

Tôi có một tệp văn bản trên máy cục bộ của mình được tạo bởi tập lệnh Python hàng ngày chạy bằng cron. 

Tôi muốn thêm một chút mã để tệp đó được gửi an toàn đến máy chủ của tôi qua SSH.

85
Alok

Nếu bạn muốn cách tiếp cận đơn giản, điều này nên làm việc.

Trước tiên, bạn sẽ muốn ".c Đóng ()" tệp để bạn biết rằng nó được chuyển sang đĩa từ Python.

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

Bạn cần tạo (trên máy nguồn) và cài đặt (trên máy đích) trước một khóa ssh để scp tự động được xác thực bằng khóa ssh công khai của bạn (nói cách khác, vì vậy tập lệnh của bạn không yêu cầu mật khẩu) . 

ví dụ ssh-keygen

39
pdq

Để thực hiện điều này trong Python (tức là không gói scp thông qua quy trình con.Popen hoặc tương tự) với Paramiko library, bạn sẽ làm một cái gì đó như thế này:

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

(Bạn có thể muốn xử lý các máy chủ không xác định, lỗi, tạo bất kỳ thư mục cần thiết, v.v.).

129
Tony Meyer

Bạn có thể sử dụng mô đun quy trình con . Một cái gì đó như thế này:

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

Trong đó destination có lẽ có dạng [email protected]remotehost:remotepath. Cảm ơn @ Charles Duffy đã chỉ ra điểm yếu trong câu trả lời ban đầu của tôi, đã sử dụng một đối số chuỗi đơn để chỉ định thao tác scp Shell=True - sẽ không xử lý khoảng trắng trong đường dẫn.

Tài liệu mô-đun có ví dụ về kiểm tra lỗi mà bạn có thể muốn thực hiện cùng với thao tác này.

Đảm bảo rằng bạn đã thiết lập thông tin xác thực phù hợp để bạn có thể thực hiện không giám sát, không mật khẩu giữa các máy . Có một câu hỏi stackoverflow cho điều này đã .

28
Blair Conrad

Có một vài cách khác nhau để tiếp cận vấn đề:

  1. Gói chương trình dòng lệnh
  2. sử dụng thư viện Python cung cấp các khả năng SSH (ví dụ: - Paramiko hoặc Twisted Conch )

Mỗi cách tiếp cận có những quirks riêng. Bạn sẽ cần thiết lập các khóa SSH để kích hoạt đăng nhập không cần mật khẩu nếu bạn đang gói các lệnh hệ thống như "ssh", "scp" hoặc "rsync." Bạn có thể nhúng mật khẩu vào tập lệnh bằng Paramiko hoặc một số thư viện khác, nhưng bạn có thể thấy thiếu tài liệu gây khó chịu, đặc biệt là nếu bạn không quen với những điều cơ bản của kết nối SSH (ví dụ: trao đổi khóa, đại lý, v.v.). Có lẽ không cần phải nói rằng các khóa SSH hầu như luôn là một ý tưởng tốt hơn mật khẩu cho loại công cụ này.

LƯU Ý: thật khó để đánh bại rsync nếu bạn có kế hoạch chuyển tệp qua SSH, đặc biệt nếu phương án thay thế là scp cũ đơn giản.

Tôi đã sử dụng Paramiko với mục đích thay thế các cuộc gọi hệ thống nhưng thấy mình bị thu hút bởi các lệnh được bao bọc do tính dễ sử dụng và sự quen thuộc ngay lập tức. Bạn có thể khác. Tôi đã cho Conch một lần trước đây nhưng nó không hấp dẫn tôi.

Nếu chọn đường dẫn gọi hệ thống, Python cung cấp một loạt các tùy chọn như os.system hoặc các mô đun lệnh/quy trình con. Tôi sẽ sử dụng mô đun quy trình con nếu sử dụng phiên bản 2.4+.

10
Michael

Đạt được cùng một vấn đề, nhưng thay vì "hack" hoặc mô phỏng dòng lệnh:

Tìm thấy câu trả lời này ở đây .

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

Bạn có thể làm một cái gì đó như thế này, để xử lý cả việc kiểm tra khóa Máy chủ

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

fabric có thể được sử dụng để tải lên các tệp qua 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
jfs

Bạn có thể sử dụng gói chư hầu, được thiết kế chính xác cho việc này.

Tất cả bạn cần là cài đặt chư hầu và làm

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

Ngoài ra, nó sẽ giúp bạn tiết kiệm thông tin xác thực và không cần phải nhập lại nhiều lần.

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

một cách tiếp cận rất đơn giản là như sau: 

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

không có thư viện python được yêu cầu (chỉ os) và nó hoạt động

0
Roberto Marzocchi

Hãy thử điều này nếu bạn không sử dụng chứng chỉ 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

Tôi đã sử dụng sshfs để gắn thư mục từ xa thông qua ssh và shutil để sao chép các tệp:

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

Sau đó trong trăn:

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

Phương pháp này có lợi thế là bạn có thể truyền dữ liệu qua nếu bạn đang tạo dữ liệu thay vì lưu trữ cục bộ và gửi một tệp lớn.

0
Jonno_FTW

Gọi lệnh scp qua quy trình con không cho phép nhận báo cáo tiến trình bên trong tập lệnh. pexpect có thể được sử dụng để trích xuất thông tin đó:

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

Xem tệp sao chép python trong mạng cục bộ (linux -> linux)

0
jfs