【问题标题】:Problems using Python to SCP transfer files on Windows using os, Popen, and Paramiko在 Windows 上使用 os、Popen 和 Paramiko 使用 Python 到 SCP 传输文件的问题
【发布时间】:2019-11-20 02:54:31
【问题描述】:

我正在尝试让 Python 脚本通过 SCP 将文件传输到我拥有 root 访问权限且没有密码的 SSH 服务器。我在 Windows 上并且正在运行;

scp test.txt root@<ip-address>:/data

像魅力一样工作。

我尝试了几种不同的方法来让 Python 做到这一点,但无论如何我都会遇到麻烦:

  1. os:

    import os
    my_scp = r'C:\Windows\System32\OpenSSH\scp.exe'
    os.system(my_scp + ' test.txt root@<ip-address>:/data')
    

    我明白了:

    找不到指定的路径(翻译后的措辞可能不同)

  2. Popen:

    import subprocess
    p = subprocess.Popen(['scp', 'test.txt', 'root@<ip-address>:/data'])
    sts = os.waitpid(p.pid, 0)`
    

    我明白了:

    FileNotFoundError: [WinError 2] 找不到指定的文件(再次翻译)

    我尝试了多种方式指向OpenSSH\scp.exe,但都无济于事。

  3. 与帕拉米科:

    from paramiko import SSHClient
    from scp import SCPClient
    ssh = SSHClient()
    ssh.load_system_host_keys()
    ssh.connect('root@<ip-address>:data')
    with SCPClient(ssh.get_transport()) as scp:
        scp.put('test.txt', 'test.txt')`
    

    我明白了:

    Traceback (most recent call last):
      File ".\my_script.py", line 6, in <module>
        ssh.connect('root@<ip-address>:data')
      File "C:\Users\myself\AppData\Local\Programs\Python\Python37-32\lib\site-packages\paramiko\client.py", line 334, in connect
        to_try = list(self._families_and_addresses(hostname, port))
      File "C:\Users\myself\AppData\Local\Programs\Python\Python37-32\lib\site-packages\paramiko\client.py", line 204, in _families_and_addresses
        hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM
      File "C:\Users\myself\AppData\Local\Programs\Python\Python37-32\lib\socket.py", line 748, in getaddrinfo
        for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
    socket.gaierror: [Errno 11003] getaddrinfo failed
    

我在 Windows 10 中运行 Python 3.7.3。


更新 - 运行 scp -v:

PS C:\scp_test> scp -v test.txt root@169.254.108.26:/data
Executing: program ssh.exe host 169.254.108.26, user root, command scp -v -t /data
OpenSSH_for_Windows_7.6p1, LibreSSL 2.6.4
debug1: Connecting to 169.254.108.26 [169.254.108.26] port 22.
debug1: Connection established.
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_rsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ed25519-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_for_Windows_7.6
debug1: Remote protocol version 2.0, remote software version dropbear_2017.75
debug1: no match: dropbear_2017.75
debug1: Authenticating to 169.254.108.26:22 as 'root'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256@libssh.org
debug1: kex: host key algorithm: ecdsa-sha2-nistp521
debug1: kex: server->client cipher: aes128-ctr MAC: hmac-sha2-256 compression: none
debug1: kex: client->server cipher: aes128-ctr MAC: hmac-sha2-256 compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ecdsa-sha2-nistp521 SHA256:RNaIuHs4U+5p8kQrcB+0pwCoKab3j6DNCk5hShNzpj4
debug1: Host '169.254.108.26' is known and matches the ECDSA host key.
debug1: Found key in C:\\Users\\myself/.ssh/known_hosts:4
debug1: rekey after 4294967296 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey after 4294967296 blocks
debug1: pubkey_prepare: ssh_get_authentication_socket: No such file or directory
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentication succeeded (none).
Authenticated to 169.254.108.26 ([169.254.108.26]:22).
debug1: channel 0: new [client-session]
debug1: Entering interactive session.
debug1: pledge: network
debug1: Sending command: scp -v -t /data
Sending file modes: C0666 5430 test.txt
Sink: C0666 5430 test.txt
test.txt
100% 5430     5.3KB/s   00:00
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 7080, received 1376 bytes, in -7.0 seconds
debug1: Exit status 0

更新二:我通过将 Python 重新安装为 64 位并使用 os 调用 OpenSSH 来运行它。

【问题讨论】:

  • 如果文件已经存在,第二种情况应该可以工作。大概是您从与包含您要复制的文件的目录不同的目录运行它,或者您拼错了它的名称。
  • 问题是调用运行 Python 32 位的 64 位 OpenSSH,正如下面的 Martin Prikryl 指出的那样。重新安装 Python 64 位后,案例 1 和 2 都有效。
  • 你已经使用了C:\Windows\sysnative\OpenSSH\sftp——而且你不需要重新安装 Python。
  • 我确实尝试了该选项,但它引发了错误。我不记得具体是什么 - 它确实运行了 OpenSSH,但不会传输文件。

标签: python windows ssh paramiko scp


【解决方案1】:

您错误地使用了 Paramiko SSHClient.connect

SSHClient.connect 的第一个参数是hostname(在您的情况下也可以是 IP 地址)。没有用户名或其他任何内容。用户名转到 username 参数。目标路径(与 SSH 连接无关)仅到达 SCPClient.put

这应该可行:

ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('<ip-address>', username='root')
with SCPClient(ssh.get_transport()) as scp:
    scp.put('test.txt', '/data/test.txt')

关于您尝试使用scp:只是一个疯狂的猜测,但我假设您使用的是 OpenSSH 的 Win32-OpenSSH 构建。它仅提供 64 位版本。如果您使用 32 位 Python,则找不到 64 位 OpenSSH 工具,例如 scp,因为它们是 C:\Windows\System32 的 64 位版本。您可以通过魔术名称C:\Windows\sysnative\OpenSSH\sftp 访问它。阅读File System Redirector。尽管您不应该运行控制台应用程序来实现 SCP。使用原生 Python SCP 实现,例如 SCPClient

【讨论】:

  • 嗨 Martin,感谢您指出使用 Paramiko 的错误。但是,在此修复后它不起作用。我得到完全相同的错误信息。您对位版本是正确的 - 32 位 Python 和 64 位 OpenSSH。您对 Paramiko 有任何其他想法,或者是否将 Python 重新安装为 64 位并使用 OpenSSH 是更简单的选择?
  • 我的回答清楚地表明你应该做ssh.connect('&lt;ip-address&gt;', username='root'),而不是ssh.connect('root@&lt;ip-address&gt;', username='root')——connect 的第一个参数是hostname(在你的情况下也可以是 IP 地址)。没有用户名或其他任何内容。阅读文档。它在我的答案中链接。
  • 你是绝对正确的 - 我有 'root@IP' 正如我所遵循的示例中所建议的那样 - 哦! :-( 清除之后,现在我得到:raise SSHException("No authentication methods available")。由于我没有我要连接的设备的密码,我想我需要建立 SSH-keys两个设备..?
  • 您写道scp 有效。它必须以某种方式进行身份验证。你不知道怎么做?它很可能使用私钥(您会知道它是否使用了密码)。所以在 Paramiko 中使用相同的键。
  • 我不知道它是如何认证的。我自己没有配置服务器——据我所知,设备中嵌入了一个树莓派,我通过 USB 连接到它。我确定我没有在我的客户端计算机上设置任何密钥。
【解决方案2】:

如果 Win10 64 位和 Python 32 位 (3.8) 找到解决方案:

a = 'scp -r -i "path_to_your_key" path_to_file_want_to_send login@server_or_ip:path_on_server'
#  Also work if add ssh line to the a
# a += "\nssh -i path_to_your_key login@server_or_ip \"SOME COMMAND TO DO ON SERVER\""

filename = "sendjob.bat"
s = open(filename, "w+")
s.write(a)
s.close()
os.system('c:\windows\syswow64\cmd.exe /c c:\windows\sysnative\cmd.exe /c start ' + filename)

我的配置: Win10办公笔记本无root权限 我需要将文件发送到 Linux 服务器,然后在那里做一些事情。

【讨论】:

    【解决方案3】:

    第一种方法的一个可能问题是您需要将反斜杠加倍。反斜杠在字符串中用于表示特殊字符,但如果你只想要一个反斜杠,你希望有两个

    import os
    my_scp = r'C:\\Windows\\System32\\OpenSSH\\scp.exe'
    os.system(my_scp + ' test.txt root@<ip-address>:/data')
    

    【讨论】:

    • 您不需要在原始字符串中转义反斜杠。
    • 啊,是的,你是对的。没看到那是我的错
    猜你喜欢
    • 1970-01-01
    • 2012-08-29
    • 2012-10-05
    • 1970-01-01
    • 2021-08-13
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    • 2013-03-12
    相关资源
    最近更新 更多