用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真是太好了!

相关推荐
CCblandy7 分钟前
前缀缓存命中率不靠引擎靠排列:本机仿真 3 轮,易变字段放开头 98.0%→0.0%
人工智能·python·算法·自然语言处理·性能优化
Sakura_j_h_32 分钟前
给 FastAPI 接大模型:超时、重试和 token 成本该怎么管
python·大模型·fastapi·超时重试·token计费
forest_0936 分钟前
用Python复刻ClaudeDuet:主动式Agent四件套,定时晨报、后台巡检、危险动作审批(附完整可运行代码)
人工智能·python·架构·prompt·agi
小小张说故事1 小时前
Python 的函数调用到底贵在哪?拆开一次 call:51 纳秒栈帧与 *args 的 40 纳秒罚单
python
2401_885885042 小时前
国际语音C#接口怎么写?.NET环境下实现国际语音验证码批量下发
开发语言·c#·.net
程序猿乐锅2 小时前
【从0-1学习Python | 第七篇】Python 面向对象基础
开发语言·笔记·后端·python·学习·1024程序员节
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 查询圈子个人动态:查询我的动态需求分析
java·开发语言·交友
lzqrzpt2 小时前
太阳能控制器选型要点:电路工艺与工程适配技术解析
python·1024程序员节
凯瑟琳.奥古斯特2 小时前
力扣1016高效解法:剪枝优化技巧
开发语言·c++·算法·leetcode·职场和发展
databook3 小时前
时间序列数据中,如何找出缺失值
python·数据分析