如何使用 SCP 或 SSH 将文件复制到 Python 中的远程服务器?

发布于 2024-07-05 09:19:47 字数 99 浏览 11 评论 0原文

我的本地计算机上有一个文本文件,该文件是由 cron 中运行的日常 Python 脚本生成的。

我想添加一些代码,以便通过 SSH 将该文件安全地发送到我的服务器。

I have a text file on my local machine that is generated by a daily Python script run in cron.

I would like to add a bit of code to have that file sent securely to my server over SSH.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

浪漫之都 2024-07-12 09:19:48

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

Try this if you wan't to use SSL certificates:

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!')
刘备忘录 2024-07-12 09:19:48

有点 hacky,但以下应该有效:)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" [email protected]:"+serverPath)

Kind of hacky, but the following should work :)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" [email protected]:"+serverPath)
风月客 2024-07-12 09:19:48

通过子进程调用 scp 命令不允许接收脚本内的进度报告。 pexpect 可用于提取该信息:

import pipes
import re
import pexpect # $ pip install pexpect

def progress(locals):
    # extract percents
    print(int(re.search(br'(\d+)%

请参阅本地网络中的 python 复制文件 (linux -> linux)

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

Calling scp command via subprocess doesn't allow to receive the progress report inside the script. pexpect could be used to extract that info:

import pipes
import re
import pexpect # $ pip install pexpect

def progress(locals):
    # extract percents
    print(int(re.search(br'(\d+)%

See python copy file in local network (linux -> linux)

, locals['child'].after).group(1))) command = "scp %s %s" % tuple(map(pipes.quote, [srcfile, destination])) pexpect.run(command, events={r'\d+%': progress})

See python copy file in local network (linux -> linux)

讽刺将军 2024-07-12 09:19:47

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

您可能想要处理未知的主机、错误、创建任何必要的目录等等)。

To do this in Python (i.e. not wrapping scp through subprocess.Popen or similar) with the Paramiko library, you would do something like this:

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

(You would probably want to deal with unknown hosts, errors, creating any directories necessary, and so on).

痴情换悲伤 2024-07-12 09:19:47

您可以调用 scp bash 命令(它通过 SSH) 和 subprocess.run

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

如果您要在同一 Python 程序中创建要发送的文件,则需要调用在用于打开文件的 with 块之外执行 subprocess.run 命令(或者先在文件上调用 .close(),如果您这样做的话)没有使用 with 块),因此您知道它已从 Python 刷新到磁盘。

您需要预先生成(在源计算机上)并安装(在目标计算机上)ssh 密钥,以便 scp 自动使用您的公共 ssh 密钥进行身份验证(换句话说,这样您的脚本就不会要求输入密码) 。

You can call the scp bash command (it copies files over SSH) with subprocess.run:

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

If you're creating the file that you want to send in the same Python program, you'll want to call subprocess.run command outside the with block you're using to open the file (or call .close() on the file first if you're not using a with block), so you know it's flushed to disk from Python.

You need to generate (on the source machine) and install (on the destination machine) an ssh key beforehand so that the scp automatically gets authenticated with your public ssh key (in other words, so your script doesn't ask for a password).

空城旧梦 2024-07-12 09:19:47

您可能会使用子进程模块。 像这样的:

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 问题

You'd probably use the subprocess module. Something like this:

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

Where destination is probably of the form user@remotehost:remotepath. Thanks to
@Charles Duffy for pointing out the weakness in my original answer, which used a single string argument to specify the scp operation shell=True - that wouldn't handle whitespace in paths.

The module documentation has examples of error checking that you may want to perform in conjunction with this operation.

Ensure that you've set up proper credentials so that you can perform an unattended, passwordless scp between the machines. There is a stackoverflow question for this already.

债姬 2024-07-12 09:19:47

遇到了同样的问题,但不是“黑客攻击”或模拟命令行:

此处找到了这个答案。

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

Reached the same problem, but instead of "hacking" or emulating command line:

Found this answer here.

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')
江挽川 2024-07-12 09:19:47

有几种不同的方法可以解决该问题:

  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 模块。

There are a couple of different ways to approach the problem:

  1. Wrap command-line programs
  2. use a Python library that provides SSH capabilities (eg - Paramiko or Twisted Conch)

Each approach has its own quirks. You will need to setup SSH keys to enable password-less logins if you are wrapping system commands like "ssh", "scp" or "rsync." You can embed a password in a script using Paramiko or some other library, but you might find the lack of documentation frustrating, especially if you are not familiar with the basics of the SSH connection (eg - key exchanges, agents, etc). It probably goes without saying that SSH keys are almost always a better idea than passwords for this sort of stuff.

NOTE: its hard to beat rsync if you plan on transferring files via SSH, especially if the alternative is plain old scp.

I've used Paramiko with an eye towards replacing system calls but found myself drawn back to the wrapped commands due to their ease of use and immediate familiarity. You might be different. I gave Conch the once-over some time ago but it didn't appeal to me.

If opting for the system-call path, Python offers an array of options such as os.system or the commands/subprocess modules. I'd go with the subprocess module if using version 2.4+.

一花一树开 2024-07-12 09:19:47

使用外部资源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')

Using the external resource 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')
§普罗旺斯的薰衣草 2024-07-12 09:19:47

我使用 sshfs 通过 ssh 挂载远程目录,并且 shutil 复制文件:

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

然后在 python 中:

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

此方法的优点是您可以通过 if 流式传输数据您正在生成数据,而不是在本地缓存并发送单个大文件。

I used sshfs to mount the remote directory via ssh, and shutil to copy the files:

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

Then in python:

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

This method has the advantage that you can stream data over if you are generating data rather than caching locally and sending a single large file.

始终不够爱げ你 2024-07-12 09:19:47

一个非常简单的方法如下:

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

不需要 python 库(仅操作系统),并且它可以工作,但是使用此方法依赖于安装另一个 ssh 客户端。 如果在另一个系统上运行,这可能会导致不良行为。

A very simple approach is the following:

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

No python library are required (only os), and it works, however using this method relies on another ssh client to be installed. This could result in undesired behavior if ran on another system.

も星光 2024-07-12 09:19:47

您可以使用 vassal 包,它就是专门为此设计的。

您所需要做的就是安装 vassal 并执行以下操作

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

,此外,它将保存您的身份验证凭据,并且不需要一次又一次地输入它们。

You can use the vassal package, which is exactly designed for this.

All you need is to install vassal and do

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

Also, it will save you authenticate credential and don't need to type them again and again.

青衫负雪 2024-07-12 09:19:47

您可以执行类似的操作来处理主机密钥检查

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

You can do something like this, to handle the host key checking as well

import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path username@hostname:remote_path")
夜还是长夜 2024-07-12 09:19:47

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

fabric could be used to upload files vis 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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文