簡體   English   中英

如何使用 SCP 或 SSH 將文件復制到 Python 中的遠程服務器?

[英]How to copy a file to a remote server in Python using SCP or SSH?

我的本地機器上有一個文本文件,它是由在 cron 中運行的每日 Python 腳本生成的。

我想添加一些代碼,以便通過 SSH 將該文件安全地發送到我的服務器。

要在 Python 中使用Paramiko庫(即不通過 subprocess.Popen 或類似方法包裝 scp),您可以執行以下操作:

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

(您可能想要處理未知主機、錯誤、創建任何必要的目錄等)。

您可以撥打scp bash命令(則復制文件SSH )與subprocess.run

import subprocess
subprocess.run(["scp", FILE, "USER@SERVER:PATH"])
#e.g. subprocess.run(["scp", "foo.bar", "joe@srvr.net:/path/to/foo.bar"])

如果要在同一個 Python 程序中創建要發送的文件,則需要在用於打開文件的with塊之外調用subprocess.run命令(或在文件上調用.close()首先,如果您沒有使用with塊),那么您就知道它是從 Python 刷新到磁盤的。

您需要預先生成(在源機器上)並安裝(在目標機器上)一個 ssh 密鑰,以便 scp 自動使用您的公共 ssh 密鑰進行身份驗證(換句話說,這樣您的腳本就不會要求輸入密碼) .

您可能會使用subprocess 模塊 像這樣的東西:

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

其中destination可能是user@remotehost:remotepath的形式。 感謝@Charles Duffy 指出了我原始答案中的弱點,它使用單個字符串參數來指定 scp 操作shell=True - 這不會處理路徑中的空格。

模塊文檔包含您可能希望與此操作一起執行的錯誤檢查示例。

確保您已設置正確的憑據,以便您可以在機器之間執行無人值守、無密碼的 scp 已經有一個關於這個stackoverflow 問題

有幾種不同的方法可以解決這個問題:

  1. 包裝命令行程序
  2. 使用提供 SSH 功能的 Python 庫(例如 - ParamikoTwisted Conch

每種方法都有自己的怪癖。 如果您要封裝“ssh”、“scp”或“rsync”等系統命令,則需要設置 SSH 密鑰以啟用無密碼登錄。 您可以使用 Paramiko 或其他一些庫在腳本中嵌入密碼,但您可能會發現缺少文檔令人沮喪,特別是如果您不熟悉 SSH 連接的基礎知識(例如 - 密鑰交換、代理等)。 不用說,對於這類東西,SSH 密鑰幾乎總是比密碼更好的主意。

注意:如果您計划通過 SSH 傳輸文件,它很難擊敗 rsync,尤其是如果替代方案是普通的舊 scp。

我使用 Paramiko 時着眼於替換系統調用,但發現由於它們的易用性和直接熟悉性,我發現自己被包裝的命令所吸引。 你可能不一樣。 前段時間我給了海螺一次,但它對我沒有吸引力。

如果選擇系統調用路徑,Python 會提供一系列選項,例如 os.system 或 commands/subprocess 模塊。 如果使用版本 2.4+,我會使用 subprocess 模塊。

遇到了同樣的問題,但不是“黑客”或模擬命令行:

在這里找到了這個答案。

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

你也可以做這樣的事情來處理主機密鑰檢查

import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path username@hostname:remote_path")

fabric可用於通過 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()

您可以使用專為此設計的 vassal 包。

您只需要安裝 vassal 並執行

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

此外,它會保存您的身份驗證憑據,而無需一次又一次地鍵入它們。

使用外部資源paramiko;

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

我使用sshfs通過ssh掛載遠程目錄, shutil復制文件:

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

然后在python中:

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

這種方法的優點是,如果您正在生成數據,而不是在本地緩存並發送單個大文件,則可以流式傳輸數據。

如果您不想使用 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!')

通過子進程調用scp命令不允許在腳本內接收進度報告。 pexpect可用於提取該信息:

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

查看本地網絡中的python復制文件(linux -> linux)

一個非常簡單的方法如下:

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

不需要 python 庫(只有 os),它可以工作,但是使用此方法依賴於要安裝的另一個 ssh 客戶端。 如果在另一個系統上運行,這可能會導致意外行為。

有點hacky,但以下應該有效:)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM