• python 终端模拟模块 pexpect


    简单介绍
    pexpect是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python 模块。它可以用来实现与ssh, ftp, telnet等程序的自动交互,参考官方文档:https://pexpect.readthedocs.io/en/stable/

    安装均可以使用pip进行

    注意:windows和linux安装模块是不同的。如下:
    在linux下安装:pip3 install pexpect
    在windows下安装: pip3.exe install winpexpect

    在windows系统里创建子程序是:
    import winpexpect
    child = winpexpect.winspawn('command')
    另:run(), pxssh()均不可使用

    在linux系统里创建子程序是:
    import pexpect
    child = pexpect.spawn('cmd')

    模块内主要的类/函数介绍

    spawn / winspawn 类
    作用:可以实现更复杂的交互,通过生成子程序进行sendline(发送命令)与expect(返回操作符)进行交互。
    class spawn
    def __init__(self, command, args=[], timeout=30, maxread=2000,
    searchwindowsize=None, logfile=None, cwd=None, env=None,
    username=None, domain=None, password=None)

    个别参数解释:
    timeout:交互等待的超时值,默认30秒
    maxread:设置read buffer大小,
    searchwindowsize:从输入缓冲区中进行模式匹配的位置,默认从开始匹配。
    logfile:指定日志的记录位置

    注意:pexpect不支持管道,重定向或通配符,如果需要使用,需要重新打开一个shell
    简单用法:
    # 第一步创建子程序,输入执行的操作命令,我这里是以telnet远程终端为例
    child = pexpect.spawn('telnet ipaddress')
    # 第二步从子命令返回的结果中进行匹配,语法:expect(pattern, timeout=-1),

      pattern参数说明:可以为字符串,正则表达式,EOF,TIMEOUT,或者是以上类型的列表,若只提供字符串,匹配成功后返回0,若提供列表,匹配成功后返回列表的索引序号。未匹配成功,则会引发异常

    timeout:为-1 使用默认的超时期限,设置为NONE,将阻塞至返回信息
    child.expect('password:')
    # 第三步匹配成功后,发送交互信息,这里发送密码
    child.sendline(mypassword)

    获取命令执行结果主要由3个基本属性。

    child.before:输出匹配点之前的命令执行结果

    child.after:输出匹配成功后的匹配点内容,如标识符:hostname#>

    child.match:保存已匹配的匹配点对象,可以使用string,打印命令的执行结果。

    pxssh类
    是pexpect的派生类,用于建立ssh连接,比pexpect直接使用ssh时简单一些,内建3个方法:
    login() 建立到目标机器的ssh连接;
    logout() 释放该连接;
    prompt() 等待提示符,通常用于等待命令执行结束。

    pexpect.EOF 异常错误
    获取pexpect错误信息,可能会有两种 EOF 异常被抛出,但是他们除了显示的信息不同,其实本质上是相同的。为了实用的目的,不需要区分它们,他们只是给了些关于你的 python 程序到底运行在哪个平台上的额外信息,这两个显示信息是:
    End Of File (EOF) in read(). Exception style platform.
    End Of File (EOF) in read(). Empty string style platform.
    有些 UNIX 平台,当你读取一个处于 EOF 状态的文件描述符时,会抛出异常,其他 UNIX 平台,却只会静静地返回一个空字符串来表明该文件已经达到了状态。

    pexpect.TIMEOUT异常错误
    如果子程序没有在指定的时间内生成任何 output,那么 expect() 和 read() 都会产生 TIMEOUT 异常。超时默认是 30s,可以在 expect() 和 spawn 构造函数初始化时指定为其它时间
    child.expect('password:', timeout=120) # 等待 120s
    如果你想让 expect() 和 read() 忽略超时限制,即无限期阻塞住直到有 output 产生,设置 timeout 参数为 None。
    代码如:
    child = pexpect.spawn( "telnet 域名" )
    child.expect( "login", timeout=None )

    以上两个错误可以使用try语句来处理报错
    try:
    child=pexpect.spawn('telnet ip',timeout=5)
    child.logfile = log
    child.logfile_send=sys.stdout
    child.expect("New password:")
    child.sendline(mypassword)
    child.expect("Retype new password:")
    child.sendline(mypassword)
    child.expect("passwd: all authentication tokens updated successfully.")
    except pexpect.EOF:
    pass
    except pexpect.TIMEOUT:
    pass

    实例:自动登陆ftp

     1 import pexpect
     2 # 即将 ftp 所要登录的远程主机的域名
     3 ipAddress = '域名名称'
     4 # 登录用户名
     5 loginName = 'username'
     6 # 用户名密码
     7 loginPassword = 'password'
     8 # 拼凑 ftp 将要执行的命令
     9 cmd = 'ftp ' + ipAddress
    10 # 利用 cmd 命令作为 spawn 类构造函数的参数,生成一个 spawn 类的对象
    11 child = pexpect.spawn(cmd)
    12 # 期望具有提示输入用户名的字符出现
    13 index = child.expect(["(?i)name", "(?i)Unknown host", pexpect.EOF, pexpect.TIMEOUT])
    14 # 匹配到了列表索引为0的字符串 "(?i)name",表明接下来要输入用户名
    15 if index == 0:
    16     # 发送登录用户名 + 换行符给子程序.
    17     child.sendline(loginName)
    18     # 期望 "(?i)password" 具有提示输入密码的字符出现.
    19     index = child.expect(["(?i)password", pexpect.EOF, pexpect.TIMEOUT])
    20     # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出.
    21     if (index != 0):
    22         print "ftp login failed"
    23         child.close(force=True)
    24     # 匹配到了密码提示符,发送密码 + 换行符给子程序.
    25     child.sendline(loginPassword)
    26     # 期望登录成功后,提示符 "ftp>" 字符出现.
    27     index = child.expect( ['ftp>', 'Login incorrect', 'Service not available',
    28     pexpect.EOF, pexpect.TIMEOUT])
    29     # 匹配到了 'ftp>',登录成功.
    30     if (index == 0):
    31         print 'Congratulations! ftp login correct!'
    32         # 发送 'bin'+ 换行符给子程序,表示接下来使用二进制模式来传输文件.
    33         child.sendline("bin")
    34         print 'getting a file...'
    35         # 向子程序发送下载文件 rmall 的命令.
    36         child.sendline("get rmall")
    37         # 期望下载成功后,出现 'Transfer complete.*ftp>',其实下载成功后,
    38         # 会出现以下类似于以下的提示信息:
    39         #    200 PORT command successful.
    40         #    150 Opening data connection for rmall (548 bytes).
    41         #    226 Transfer complete.
    42         #    548 bytes received in 0.00019 seconds (2.8e+03 Kbytes/s)
    43         # 所以直接用正则表达式 '.*' 将 'Transfer complete' 和提示符 'ftp>' 之间的字符全省去.
    44         index = child.expect( ['Transfer complete.*ftp>', pexpect.EOF, pexpect.TIMEOUT] )
    45         # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出.
    46         if (index != 0):
    47             print "failed to get the file"
    48             child.close(force=True)
    49         # 匹配到了 'Transfer complete.*ftp>',表明下载文件成功,打印成功信息,并输入 'bye',结束 ftp session.
    50         print 'successfully received the file'
    51         child.sendline("bye")
    52     # 用户名或密码不对,会先出现 'Login incorrect',然后仍会出现 'ftp>',但是 pexpect 是最小匹配,不是贪婪匹配,
    53     # 所以如果用户名或密码不对,会匹配到 'Login incorrect',而不是 'ftp>',然后程序打印提示信息并退出.
    54     elif (index == 1):
    55         print "You entered an invalid login name or password. Program quits!"
    56         child.close(force=True)
    57     # 匹配到了 'Service not available',一般表明 421 Service not available, remote server has closed connection,程序打印提示信息并退出.
    58     # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出.
    59     else:
    60         print "ftp login failed! index = " + index
    61         child.close(force=True)
    View Code

    实例:自动登陆交换机执行一条命令后退出,最好在linux系统下进行测试,在windows下使用winpexpect不好用

     1 #!/opt/python3/bin/python3
     2 # _*_ coding:utf-8 _*_
     3 # Author: Yong
     4 
     5 import pexpect
     6 # 基本信息
     7 ipAddr = '交换机IP'
     8 pwd = '交换机登陆密码'
     9 cmd = 'telnet ' + ipAddr
    10 
    11 # 连接设备,创建子进程
    12 child = pexpect.spawn(cmd, timeout=300)
    13 # 进行匹配返回标识符
    14 index = child.expect(['Password:', pexpect.EOF, pexpect.TIMEOUT])
    15 # 匹配到列表索引0的内容
    16 if index == 0:
    17     # 网络设备登陆直接提示密码,发送密码
    18     child.sendline(pwd)
    19     # 匹配返回标识符
    20     index = child.expect('<A-3F-30>')
    21     # 未匹配到标识符,退出
    22     if index != 0:
    23         exit('密码错误')
    24     print('密码验证完成')
    25     # 发送执行的命令
    26     child.sendline('display version')
    27     # 匹配返回的标识符
    28     child.expect('<A-3F-30>')
    29     # 打印命令执行结果
    30     print(child.before)
    31     # print('将telnet子程序执行权交给用户')
    32     # child.interact()
    33 
    34 else:
    35     # 匹配到EOF 或者TIMEOUT表示超过时间限制
    36     print('telnet faild, EOF OR TIMEOUT',pexpect.EOF)
    37 # 关闭连接
    38 child.close()
    View Code
  • 相关阅读:
    Gradle 配置国内镜像
    Spring_Boot 简单例子
    IDEA中代码不小心删除,或者改了半天想回退到某个特定时间怎么办?
    Java 装饰模式
    Spring中 aop的 xml配置(简单示例)
    Spring使用@AspectJ开发AOP(零配置文件)
    Redis 的简单运算
    Redis 安装 与 使用
    touch-action属性引起的探索
    select下拉框的探索(<option></option>标签中能嵌套使用其它标签吗)
  • 原文地址:https://www.cnblogs.com/zy6103/p/10222996.html
Copyright © 2020-2023  润新知