简单介绍
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
举例:
# 第一步与终端建立连接
child = pexpect.spawn(‘telnet ipaddress‘)
# 第二步等待终端返回特定内容: password:
child.expect(‘password:‘)
# 第三步根据返回内容发送命令进行交互
child.sendline(mypassword)
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 importpexpect2 #即将 ftp 所要登录的远程主机的域名
3 ipAddress = ‘域名名称‘
4 #登录用户名
5 loginName = ‘username‘
6 #用户名密码
7 loginPassword = ‘password‘
8 #拼凑 ftp 将要执行的命令
9 cmd = ‘ftp‘ +ipAddress10 #利用 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 =" +index61 child.close(force=True)
View Code
实例:自动登陆交换机执行一条命令后退出,最好在linux系统下进行测试,在windows下使用winpexpect不好用
1 #!/opt/python3/bin/python3
2 #_*_ coding:utf-8 _*_
3 #Author: Yong
4
5 importpexpect6 #基本信息
7 ipAddr = ‘交换机IP‘
8 pwd = ‘交换机登陆密码‘
9 cmd = ‘telnet‘ +ipAddr10
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(‘‘)21 #未匹配到标识符,退出
22 if index !=0:23 exit(‘密码错误‘)24 print(‘密码验证完成‘)25 #发送执行的命令
26 child.sendline(‘display version‘)27 #匹配返回的标识符
28 child.expect(‘‘)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
原文地址:/zy6103/p/10222996.html