python3 中的 Pexpect interact() 异常

Pexpect interact() exception in python3

我正在学习 Python 如果我的问题很幼稚,请见谅。

我在我的脚本中使用了 pexpect interact(),它与 python2.7 一起工作。但是当我使用 python3 或 python3.5 时,出现以下错误:

Traceback (most recent call last):
  File "ap_access.py", line 73, in <module>
    child.interact()
  File "/usr/local/lib/python3.5/dist-packages/pexpect/pty_spawn.py", line 745, in interact
    self.__interact_copy(escape_character, input_filter, output_filter)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/pty_spawn.py", line 784, in __interact_copy
    self._log(data, 'read')
  File "/usr/local/lib/python3.5/dist-packages/pexpect/spawnbase.py", line 121, in _log
    self.logfile.write(s)
TypeError: write() argument must be str, not bytes

用谷歌搜索了这个问题,但实际上与 interact() 没有任何关系,但没有得到太多信息。

# Script to log into the device and execute the required shell commands.
log_file = open('logfile.txt', 'w')
for ip in list_of_IP_addresses:
        ip1=str(ip)
        child = pexpect.spawnu('ssh '+username+'@'+ip1, log_file)
        code = child.expect(['Are you sure you want to continue connecting   (yes/no)?', 'Please login: ', 'password :', 'No route to host', pexpect.EOF, pexpect.TIMEOUT])

    if code==0:
            child.sendline('yes')
            code = child.expect(['Are you sure you want to continue connecting (yes/no)?', 'Please login: ', 'password :', 'No route to host',  pexpect.EOF, pexpect.TIMEOUT])
    if code==1:
            print("Entering the Username")
            child.sendline(username)
            code = child.expect(['Are you sure you want to continue connecting (yes/no)?', 'Please login: ', 'password :', 'No route to host', pexpect.EOF, pexpect.TIMEOUT])
    if code==2:
            print("Entering the credentials")
            child.sendline(password)
    if code==3:
            print ("Please check for reachability for ip", ip1)
            sys.exit()
    if code==4:
            print ("Looks like there is an error")
            sys.exit(0)
    if code==5:
            print ("Timeout in accessing or logging into ", ip1)
            sys.exit(0)
    child.interact()

如果能获得有关如何使 pexpect interact() 与 python3.x

一起工作的帮助,我将不胜感激

谢谢。

更新

我面临的新问题是,在我捕获输出的日志文件中看不到 ps 等具有较大输出的文件目录的命令输出。我尝试使用 "setwinsize" 设置 winsize,将 maxreadsize 设置为更大的值,但没有任何改变。

def log_separation():
    sep_file = 'Device_LOG_{}.log'.format(date.today())
    child.logfile = open(sep_file, "a")
    with open(sep_file, 'a+') as log_sep:
        log_sep.write('\n'+'\n')

def mem_cpu():
    mem_file = 'Device_LOG_{}.log'.format(date.today())
    with open(mem_file, 'a+') as cpu:
        cpu.write(str(datetime.datetime.now())+'\n')                                                cpu.write('########################################################'+'\n')
child.sendline('top -n 1')
child.expect('#')
log_separation()
child.sendline('cat /proc/meminfo')
log_separation()
child.expect('#')
child.sendline('cat /proc/slabinfo')
log_separation()
child.expect('#')
child.sendline('cat /proc/tasklets')
log_separation
child.expect('#')
child.sendline('free')
log_separation()
child.expect('#')
child.sendline('ps axww')
log_separation()
child.expect('#')
child.sendline('exit')

# Gets the set of all IP addresses in the given range
list_of_IP_addresses = get_IP_address(ip_addr_lower, ip_addr_upper)

#Opening a file to write the error logs to
log_file = open('logfile.txt', 'w')
with open('Device_Access_log.log', 'w+') as f:
# Script to log into the devices and excute the required shell commands.
    for ip in list_of_IP_addresses:
        ip1=str(ip)
        child = pexpect.spawn('ssh '+username+'@'+ip1, logfile=log_file)
        child.logfile_read = sys.stdout
        code = child.expect(['Are you sure you want to continue connecting (yes/no)?', 'Please login: ', 'password :', 'No route to host', pexpect.EOF, pexpect.TIMEOUT])
        if code==0:
            child.sendline('yes')
            code = child.expect(['Are you sure you want to continue connecting (yes/no)?', 'Please login: ', 'password :', 'No route to host',  pexpect.EOF, pexpect.TIMEOUT])
        if code==1:
            print('Entering the Username')
            child.sendline(username)
            code = child.expect(['Are you sure you want to continue connecting (yes/no)?', 'Please login: ', 'password :', 'No route to host', pexpect.EOF, pexpect.TIMEOUT]) 
        if code==2:
        print('Entering the credentials')
        child.sendline(password)
        mem_cpu()
    stats_file = 'Device_LOG_{}.log'.format(date.today())
    with open(stats_file, 'a+') as eol:
        eol.write('############################### End of log for Device '+ip1+' ###############################################'+'\n')
        eol.write('########################################################################################################'+'\n')
    if code==3:
        print ('Ip address error', ip1)
        f.write('No route to host '+ip1+'\n')
    if code==4:
                print ('Error connecting to ', ip1)
        f.write('Error connecting to '+ip1+'\n')
    if code==5:
                print ('Timeout in accessing or logging into ', ip1)
        f.write('Timeout in accessing or logging into '+ip1+'\n')

我可以看到 "free" 之前的输出,ps 命令的输出在日志文件中看不到。

我找到了解决您问题的方法here:如果您将代码的开头更改为:

for ip in list_of_IP_addresses:
    ip1=str(ip)
    child = pexpect.spawnu('ssh '+username+'@'+ip1, logfile=sys.stdout.buffer) # <-- add the logfile keyword here and use sys.stdout.buffer (byte mode) instead of sys.stdout
    ##child.logfile = sys.stdout #<-- comment out this line

应该可以。注意:我无法完整地测试您的代码。 if 案例对我不起作用,因为我使用 ssh 密钥。另外,对我来说,键盘回声将每个字母重复了三遍。总之,希望对你有所帮助。

编辑:

我没有发现任何关于键入输入的三重回显的信息,但这与您将 stdout 设置为日志文件有关。相反,如果您创建一个日志文件,问题就会消失:

mylogfile = open('logfile.txt', 'wb')
for ip in list_of_IP_addresses:
    ip1=str(ip)
    child = pexpect.spawnu('ssh '+username+'@'+ip1, logfile=mylogfile)
    child.interact()

我想我面临着同样的问题,但方式不同。我希望日志文件转到一个文件。根据我打开它的方式,我会收到不同的错误。看:

with open("ssh_run.log", "ab") as logfile:
            print( f"Connecting to {self.pxe_user}@{self.pxe_server_ipv4}\n{cmd_2_ssh}" )
            y5: Tuple = pexpect.run( cmd_2_ssh, \
                # (?i) turns on case-insensitive mode
                    events={"(?i)password: ": self.pxe_passwd + "\n"}, \
                    withexitstatus = True, logfile=logfile,
                    timeout = 20 )

我以 "ab" 模式打开日志文件。我收到的错误消息是:

TypeError: a bytes-like object is required, not 'str'

但是如果我将模式更改为 "a" 或 "at" 而不是 "ab",我会得到:

TypeError: write() argument must be str, not bytes

我也试过 open 函数调用的编码参数,但没有解决问题。

我 运行 python 3.6.9 Ubuntu 18.04.