我有两个脚本在分离时根据需要运行。一个是PyQt5 GUI应用程序的代码,第二个是与this one非常相似的代码,稍有修改就可以转换内容,以防有任何导致问题的笑脸。
基本上,当我在应用程序窗口中按某个按钮时,我希望第二个代码可以运行。
无论我多么努力地适应第二个代码,它总是会崩溃我的应用程序(或Python)。我能够达到的最远的是,当我关闭主窗口后第二个代码工作的时候 - 然后它运行,并给我我想要的结果。
我怀疑它与第二个代码中的__init__
有关,并不满意主窗口中已经有另一个__init__
正在运行?
你可以告诉我,我对Python的面向对象部分感到非常困惑,尽管无论我过去几天在这个主题上努力自学,我都无法将这两个代码放在一起。 / p>
我的应用:
#'all the necessary imports'
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.text = QWebEngineView(self)
self.proc_btn = QPushButton('Proceed')
self.userUrl = QLineEdit(self)
self.labOne = QLabel(self)
self.labTwo = QLabel(self)
self.defUrl = 'default'
self.init_ui()
def init_ui(self):
v_layout = QVBoxLayout()
h_layout = QHBoxLayout()
h_layout.addWidget(self.proc_btn)
h_layout.addWidget(self.userUrl)
v_layout.addWidget(self.text)
v_layout.addWidget(self.labOne)
v_layout.addWidget(self.labTwo)
v_layout.addLayout(h_layout)
self.labOne.setText('URL: ')
self.labTwo.setText('<ENTER LINK PLEASE>')
self.userUrl.returnPressed.connect(self.linkPut)
self.proc_btn.clicked.connect(self.doStuff)
self.setLayout(v_layout)
self.setWindowTitle('Scrapper')
self.show()
def doStuff(self):
print('Doing stuff (expecting 2nd script to be ran)')
def linkPut(self):
newText = (self.userUrl.text())
print('newText: ' + newText)
self.labTwo.setText(newText)
self.defUrl = newText
app = QApplication(sys.argv)
a_window = MainWindow()
sys.exit(app.exec_())
我需要实现的脚本:
#'all necessary imports'
class Page(QWebEnginePage):
def __init__(self, url):
self.app = QApplication(sys.argv)
QWebEnginePage.__init__(self)
self.html = ''
self.loadFinished.connect(self._on_load_finished)
self.load(QUrl(url))
self.app.exec_()
print('__init__ WORKS')
def _on_load_finished(self):
self.html = self.toHtml(self.Callable)
print('Load finished')
def Callable(self, html_str):
self.html = html_str
self.app.quit()
_nonbmp = re.compile(r'[\U00010000-\U0010FFFF]')
def _surrogatepair(match):
char = match.group()
assert ord(char) > 0xffff
encoded = char.encode('utf-16-le')
return (
chr(int.from_bytes(encoded[:2], 'little')) +
chr(int.from_bytes(encoded[2:], 'little')))
def with_surrogates(text):
return _nonbmp.sub(_surrogatepair, text)
def main():
page = Page('https://somenicepage.com/')
soup = bs.BeautifulSoup(page.html, 'html.parser'))
longStrCoded = str(soup.find("img", {"class":"pictures"}))
longStr = with_surrogates(longStrCoded)
print('long str: ' + longStr)
extract = longStr.split('src="')[1].split('"')[0]
print(extract)
if __name__ == '__main__': main()
答案 0 :(得分:0)
问题在于,在组合这两个文件时,您尝试创建QApplication
的多个实例,这是不允许的。此外,QApplication
类旨在封装整个应用程序逻辑,并负责事件处理等。您通常不应该像在Page.__init__
内部那样在其他类中创建。
通常,您可以在程序入口点附近创建并启动QApplication
。您正在第一个代码块中正确执行此操作。
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv) # Instantiate application
window = MainWindow() # The rest of your program logic should flow from here
sys.exit(app.exec_()) # Start application event loop
QtWebEngine
的异步性质会使事情变得复杂,因为在继续执行下一条指令之前,程序不会等待页面加载。我相信人们在页面类中启动QApplication
作为一种快速而肮脏(或天真)的方式来强制程序等待页面完成加载。这可能在python脚本中很好,其中Qt
仅用于QtWebEngine
评估动态网页的能力,但对于真正的Qt
应用程序来说却很糟糕。处理此问题的正确方法是通过回调或Qt
的信号和插槽系统。
基于原始类,这是一个使用回调的版本,一旦完全加载就继续处理html。
class Page(QtWebEngineWidgets.QWebEnginePage):
def __init__(self, url):
super(Page, self).__init__()
self.url = QtCore.QUrl(url)
self.callback = None
self.html = ''
self.loadFinished.connect(self.on_load_finished)
def load_html(self, callback=None):
self.callback = callback
self.load(self.url)
def on_load_finished(self):
self.toHtml(self.on_html_ready)
def on_html_ready(self, html):
self.html = html
if self.callback:
self.callback(html)
接下来,定义将处理已加载页面的回调。您可以在此处放置main()
函数中的代码。
def do_stuff(html):
soup = bs.BeautifulSoup(html, 'html.parser'))
longStrCoded = str(soup.find("img", {"class":"pictures"}))
longStr = with_surrogates(longStrCoded)
print('long str: ' + longStr)
extract = longStr.split('src="')[1].split('"')[0]
print(extract)
最后,您将在MainWindow
课程中加载这样的页面。
def doStuff(self):
self.page = Page(self.userUrl.text())
self.page.load_html(callback=do_stuff)
请注意此处使用self
。如果我们不在页面中存储页面实例,它将在加载完成之前被删除,并且永远不会调用回调。