关于Python 3.6.2:Python 3.6.2 – 多个__init__;

Python 3.6.2 - multiple __init__; multiple classes at once

我有两个脚本在分离时根据需要运行。一个是Pyqt5图形用户界面应用程序的代码,第二个是与此非常相似的代码,稍作修改,以便在出现任何引起问题的笑脸时能够转换内容。

基本上,当我按下应用程序窗口中的某个按钮时,我希望运行第二个代码。

无论我多么努力地适应第二个代码,它总是会使我的应用程序(或python)崩溃。我能做到的最远的一点是,当我关闭主窗口后第二个代码工作时,它就会运行,并给我想要的结果。

我怀疑这与第二个代码中的__init__有关,不高兴主窗口中已经有另一个__init__在运行?正如您所说,我对Python的面向对象部分非常困惑,尽管在过去几天里,无论我多么努力地在这个主题上进行自我教育,我都无法将这两个代码组合在一起。

我的应用程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#'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_())

我需要实现的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#'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()


问题是,在组合两个文件时,您试图创建多个QApplication实例,这是不允许的。此外,QApplication类旨在封装整个应用程序逻辑,并负责事件处理等。通常,您不应该在其他类中创建,就像在Page.__init__中创建一样。

通常,您将创建和启动靠近程序入口点的QApplication。您在第一个代码块中正确地执行了此操作。

1
2
3
4
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的异步特性使事情稍微复杂一点,因为您的程序在继续执行下一条指令之前不会等待页面加载。我认为人们在page类中启动QApplication是一种快速而肮脏(或幼稚)的方法,可以强制程序等待页面完成加载。在python脚本中,虽然Qt仅用于QtWebEngine评估动态网页的能力,但对于实际的Qt应用程序来说,这可能是很糟糕的做法。解决这个问题的正确方法是通过回调或Qt的信号和时隙系统。

基于您的原始类,这里有一个版本,它使用回调在HTML完全加载后继续处理它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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()函数的代码。

1
2
3
4
5
6
7
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类中加载这样的页面。

1
2
3
def doStuff(self):
    self.page = Page(self.userUrl.text())
    self.page.load_html(callback=do_stuff)

注意此处使用self。如果不将页面实例存储在类中,它将在加载完成之前被删除,并且永远不会调用回调。