用python脚本访问被网关隔离的嵌入式设备

背景

公司一台数据采集设备(下位机)里有两块ARM板,一块做UI显示(兼网关),另一块做实际的数据采集(采集板),下位机采集到数据后,用户需要先通过mobaxterm等ssh客户端连接到网关,然后在网关运行scp命令将数据文件从采集板拷贝到网关,最后再用mobaxterm的ssh browser工具将数据文件拷贝到Windows,非常麻烦,最好能脚本化。

思路

用scp下载文件需要在控制台输入密码,因此要用expect之类的工具,实现自动输入ssh密码的效果

走过的弯路

python的expect实现叫pexpect,可惜pexpect不支持Windows。

python还有一个专门适配Windows的expect实现,叫wexpect,但可能是年久失修,表现很不稳定,在win11上还行,但不支持win10,而我的开发环境是win10

wexpect官方示例代码

python 复制代码
import wexpect
child = wexpect.spawn('cmd.exe')
child.expect('>')
child.sendline('ls')
child.expect('>')
print(child.before)
child.sendline('exit')

官方示例运行异常信息

复制代码
Traceback (most recent call last):
  File "D:/work_dir/DMM/wexpect.py", line 1, in <module>
    import wexpect
  File "D:\work_dir/DMM\wexpect.py", line 2, in <module>
    child = wexpect.spawn('cmd.exe')
AttributeError: partially initialized module 'wexpect' from 'D:\work_dir/DMM\wexpect.py' has no attribute 'spawn' (most likely due to a circular import)

wexpect版本4.0.0,python版本3.14.2,希望解决上述问题的朋友可以将方法分享出来。

求助豆包

在上面2种expect上花了很长时间没有进展,无奈询问豆包

复制代码
怎样在Windows上实现自动输入ssh密码的python脚本?

然后豆包给了我详尽的回答,其中包括2种路线,一种是paramiko,另一种是expect,且推荐第一种。

我试了豆包的expect脚本,发现也跑不起来,不过报错信息没我那么初级,豆包的wexpect脚本

python 复制代码
import wexpect

def ssh_with_wexpect(host, user, pwd):
    cmd = f"ssh {user}@{host}"
    # 启动ssh进程
    child = wexpect.spawn(cmd)
    try:
        # 匹配密码提示,自动输入
        child.expect("password:", timeout=10)
        child.sendline(pwd)
        # 匹配登录成功提示符(根据你的服务器改,比如 # $ >)
        child.expect(r"[#$>]", timeout=5)
        print("登录成功,当前终端输出:")
        print(child.before.decode())

        # 执行远程命令
        child.sendline("df -h")
        child.expect(r"[#$>]")
        print("df -h 输出:\n", child.before.decode())

    except wexpect.ExpectTimeout:
        print("等待输入超时,密码错误或无法连接")
    finally:
        child.close()

if __name__ == "__main__":
    ssh_with_wexpect("192.168.100.30", "root", "root")

脚本执行异常信息:

复制代码
Traceback (most recent call last):
  File "D:\whp\get_adc2.py", line 9, in ssh_with_wexpect
    child.expect("password:", timeout=10)
  File "C:\Users\whp\AppData\Local\Python\pythoncore-3.14-64\Lib\site-packages\wexpect\host.py", line 732, in expect
    return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
  File "C:\Users\whp\AppData\Local\Python\pythoncore-3.14-64\Lib\site-packages\wexpect\host.py", line 745, in expect_list
    return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
  File "C:\Users\whp\AppData\Local\Python\pythoncore-3.14-64\Lib\site-packages\wexpect\host.py", line 806, in expect_loop
    raise EOF('EOF flag has been raised.')
wexpect.wexpect_util.EOF: EOF flag has been raised.

无奈尝试paramiko方法

正解:paramiko

试了下,paramiko版脚本可以正常完成ssh访问!

结合自己的需求对豆包代码做了调整,自己的需求终于实现了,代码贴出来

python 复制代码
import time
import paramiko

if __name__ == "__main__":
    # 配置你的服务器信息
    HOST = "192.168.100.30"
    PORT = 22
    USER = "root"
    PWD = "root"

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(HOST, PORT, USER, PWD)
    sftp = ssh.open_sftp()

    # 打开交互式shell
    shell = ssh.invoke_shell()
    time.sleep(0.3)
    print(shell.recv(2048).decode())

    # 发送第一条命令
    shell.send("scp root@192.168.1.10:/var/log/messages .\n")
    time.sleep(2.0)
    print(shell.recv(1024).decode())
    shell.send("root\n")
    time.sleep(2.0)
    print(shell.recv(1024).decode())

    # 发送第二条
    sftp.get("messages", "syslog")
    time.sleep(2.0)
    print(shell.recv(1024).decode())

    ssh.close()

注意:paramiko不仅实现了ssh协议,还实现了控制台shell的功能(expect的核心特性),因此可以通过给网关发送scp命令和ssh密码,实现在网关上也自动化ssh登录的效果。

总结

要想在Windows上用expect,只能安装Active Tcl,不仅要学习TCL语言,而且该发行版还是收费的,两相对比,paramiko真是太好了!

相关推荐
Python私教15 小时前
如意智影:如何让同一个人物在多个镜头里保持身份一致
人工智能·python·架构
高洁0115 小时前
智能体的“记忆”难题
python·深度学习·机器学习·transformer
三十岁老牛再出发15 小时前
8月21日总结
c++·python
longxiaozhang615 小时前
C#继承:让代码少写一点,偷懒的好方法
开发语言·c#
草莓熊Lotso16 小时前
【Linux网络加餐】手动部署:SSH 与 Web 服务实战 + 底层原理全解析
linux·运维·网络·人工智能·python·langchain·ssh
weixin_4407305016 小时前
python+request实现接口-参数化小结
开发语言·python
CHHH_HHH16 小时前
【Linux系统篇】深入解析Linux文件系统:从磁盘寻址到软硬链接
linux·服务器·开发语言·后端·ubuntu
yngsqq16 小时前
窗体快速取消
java·开发语言
Logintern0916 小时前
Celery 死信队列 Dead‑Letter Queue(DLQ)
python
Python私教16 小时前
四个入口,一条流水线:如意智影的多入口架构取舍
人工智能·python·架构