PyQt6中通过QProcess获取pagekite.py的Shell输出异常问题
问题:QProcess调用pagekite.py获取的输出与Shell运行不一致,无法更新进度条
问题背景
我用PyQt6开发程序,期望基于pagekite.py的输出来更新进度条。目前用QProcess调用该脚本并编写了输出处理函数,但直接在Shell中运行pagekite.py时输出的是友好提示信息,通过QProcess获取的stdout却是结构化日志格式,与预期不符。
输出对比
Shell运行输出
>>> Hello! This is pagekite.py v1.5.2.201011. [CTRL+C = Stop]
Connecting to front-end relay 00.00.000.00:000 ... - Relay supports 10 protocols on 23 public ports. - Raw TCP/IP (HTTP proxied) kites are available. - To enable more logging, add option: --logfile=/path/to/logfile
~<> Flying localhost:80 as https://test.pagekite.me/
<< pagekite.py [exiting] Good-bye!
### QProcess获取的stdout输出 > ``` ts=63837a93; t=2022-11-27T14:56:19; ll=7; connect=000.000.00.000:000 ts=63837a94; t=2022-11-27T14:56:20; ll=8; FE=000.000.00.000:000; err=Rejected; proto=http; reason=quota; domain=test.pagekite.me; id=s2 ts=63837a94; t=2022-11-27T14:56:20; ll=9; FE=000.000.00.000:000; ports=79,80,443, ...; protocols=http,http2,http3,https,websocket,irc,finger,httpfinger,raw; raw_ports=virtual ts=63837a94; t=2022-11-27T14:56:20; ll=a; wrote=484; wbps=114; read=992; eof=1; id=s2 ts=63837a9e; t=2022-11-27T14:56:30; ll=b; FE=000.000.00.000:000; http_ping_ms=693; win=2; uuid=222cf21b34cfd5bed67bace00000d00000dafff0; unbiased_ms=643 ts=63837ab9; t=2022-11-27T14:56:57; ll=c; FE=000.000.00.000:000; http_ping_ms=693; win=2; uuid=222cf21b34cfd5bed67bace00000d00000dafff0; unbiased_ms=64
程序代码
import time import sys from PyQt6.QtCore import QThread, QProcess from PyQt6.QtWidgets import ( QApplication, QDialog, QDialogButtonBox, QFormLayout, QLineEdit, QVBoxLayout, QPushButton, QLabel, QProgressBar, ) class ProgressBar(QProgressBar): def __init__(self, parent=None): super().__init__(parent) self.setMaximum(100) self._active = False self.setTextVisible(False) def setBar(self, i): self.setValue(i) def changeColor(self, color): css = """ ::chunk {{ background: {0}; }} """.format(color) self.setStyleSheet(css) class Window(QDialog): def __init__(self): super().__init__(parent=None) self.setWindowTitle("QDialog") dialogLayout = QVBoxLayout() formLayout = QFormLayout() confBtn = QPushButton('Configurações') self.ligarBtn = QPushButton('Iniciar o aplicativo') statusLbl = QLabel('Desligado') self.ligado = False formLayout.addRow(confBtn) formLayout.addRow(self.ligarBtn) formLayout.addRow("Status: ", statusLbl) dialogLayout.addLayout(formLayout) self.connBar = ProgressBar() self.connBar.setBar(4) self.connBar.changeColor('gray') buttons = QDialogButtonBox() buttons.addButton('Fechar', QDialogButtonBox.ButtonRole.ActionRole) dialogLayout.addWidget(self.connBar) self.ligarBtn.clicked.connect(self.iniciaPageKite) self.setLayout(dialogLayout) self.show() y, x = self.geometry().height(), self.geometry().width() self.setFixedSize(x, y) def iniciaPageKite(self): self.prcs = QProcess() self.prcs.start('py', ['-2.7', 'pagekite.py', '80', 'test.pagekite.me']) self.prcs.readyReadStandardOutput.connect(self.pgktOutputHandler) self.prcs.readyReadStandardOutput.connect(self.pgktErrorHandler) def defPrgBarPrg(self, val): self.connBar.setBar(val) def defPrgBarClr(self, clr): self.connBar.changeColor(clr) def pgktOutputHandler(self): res = self.prcs.readAllStandardOutput() resc = bytes(res).decode('utf-8') print(resc) def pgktErrorHandler(self): err = self.prcs.readAllStandardError() errc = bytes(err).decode('utf-8') print(errc) if __name__ == "__main__": app = QApplication([]) window = Window() app.exec() sys.exit()
环境信息
- Python 3.11
- Windows 11
- 使用Python 2.7运行pagekite.py
- PyQt6
解决方案
问题根源是pagekite.py会自动检测输出环境:输出到交互式Shell时显示友好的人类可读信息;输出到非交互式管道(如QProcess的stdout)时,默认输出结构化日志格式。
1. 修改启动命令强制输出友好格式
在iniciaPageKite方法中添加--logformat=human参数,同时修正错误输出的信号连接:
def iniciaPageKite(self): self.prcs = QProcess() # 添加--logformat=human参数强制输出友好格式 self.prcs.start('py', ['-2.7', 'pagekite.py', '--logformat=human', '80', 'test.pagekite.me']) self.prcs.readyReadStandardOutput.connect(self.pgktOutputHandler) # 修正:错误输出应连接到readyReadStandardError信号 self.prcs.readyReadStandardError.connect(self.pgktErrorHandler)
2. 解析输出更新进度条
修改pgktOutputHandler函数,根据友好输出的关键字更新进度条状态:
def pgktOutputHandler(self): res = self.prcs.readAllStandardOutput() resc = bytes(res).decode('utf-8') print(resc) if "Connecting to front-end relay" in resc: self.defPrgBarPrg(25) self.defPrgBarClr("yellow") elif "Flying localhost" in resc: self.defPrgBarPrg(100) self.defPrgBarClr("green") elif "err=Rejected" in resc: self.defPrgBarPrg(0) self.defPrgBarClr("red")
注意事项
- 可通过
py -2.7 pagekite.py --help确认脚本是否支持--logformat参数 - 若需同时获取结构化日志,可添加
--logfile=./pagekite.log参数将日志写入文件,再从文件读取解析
内容的提问来源于stack exchange,提问作者Gustavo Salvador
相关产品推荐
相关产品推荐

