Skip to main content
 首页 » 编程设计

python之为什么我的 PyQt 代码在多线程时不能完全执行

2024年11月24日29birdshome

我正在尝试使用 PyQt5 和多线程编写一个网络抓取工具,以便我可以并行抓取多个 url(我知道这一点:Scrape multiple urls using QWebPage 但我真的想写一个并行版本,真的看不出为什么它不起作用) 我写了这段代码:

python 
import sys 
from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtCore import * 
 
from PyQt5.QtWebEngineWidgets import QWebEnginePage 
 
import time 
 
urlb = "https://www.google.fr/" 
 
 
class Worker(QRunnable, QWebEnginePage): 
    ''' 
    Worker thread 
    ''' 
    def __init__(self, url): 
        super(Worker, self).__init__() 
        self.url = url 
     
    def _on_load_finished(self): 
        print("tfouuu") 
        self.html = self.toHtml(self.Callable) 
        print('Load finished') 
 
    def Callable(self, html_str): 
        self.html = html_str 
     
    @pyqtSlot() 
    def run(self): 
        print("a")  
        time.sleep(2) 
        print(self.url) 
        print("b") 
        QWebEnginePage.__init__(self) 
        print("c") 
        self.html = '' 
        self.loadFinished.connect(self._on_load_finished) 
        self.load(QUrl(url)) 
        print("d") 
 
class MainWindow(QMainWindow): 
 
 
    def __init__(self, *args, **kwargs): 
         
        self.threadpool = QThreadPool() 
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) 
         
        super(MainWindow, self).__init__(*args, **kwargs) 
         
        worker = Worker(urlb) 
        worker2 = Worker(urlb) 
        self.threadpool.start(worker) 
        self.threadpool.start(worker2) 
 
 
     
     
app = QApplication([]) 
window = MainWindow() 
app.exec_() 

但是我有两个问题:

  • 第一个是我的代码不停地运行(我想这与缺少 app.quit() 行有关,但我真的不知道该把它放在哪里)

  • 第二个问题主要是我的代码只打印 'a'、'b'、'c' -> 它不运行连接和加载部分

请您参考如下方法:

QWebEngineView 不能也不应该在另一个线程上运行。

相反,如果您想异步获取 html,那么您应该使用 Qt 信号:

from functools import partial 
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets 
 
 
class WebManager(QtCore.QObject): 
    def __init__(self, parent=None): 
        super(WebManager, self).__init__(parent) 
        self.pages = [] 
        self.results = [] 
 
    def load(self, url): 
        page = QtWebEngineWidgets.QWebEnginePage(self) 
        page.loadFinished.connect(self._on_load_finished) 
        self.pages.append(page) 
        page.load(QtCore.QUrl(url)) 
 
    @QtCore.pyqtSlot(bool) 
    def _on_load_finished(self, ok): 
        page = self.sender() 
        if not isinstance(page, QtWebEngineWidgets.QWebEnginePage): 
            return 
        if ok: 
            wrapper = partial(self.callable, page) 
            page.toHtml(wrapper) 
        else: 
            self.pages.remove(page) 
            page.deleteLater() 
 
    def callable(self, page, html): 
        self.pages.remove(page) 
        url = page.requestedUrl().toString() 
        page.deleteLater() 
        self.results.append((url, html)) 
        if not self.pages: 
            QtWidgets.QApplication.quit() 
 
 
if __name__ == "__main__": 
    import sys 
 
    app = QtWidgets.QApplication(sys.argv) 
 
    manager = WebManager() 
 
    pages = [] 
    format_url = "http://pyqt.sourceforge.net/Docs/PyQt5/%s.html" 
    for name in dir(QtWebEngineWidgets): 
        if name.startswith("Q"): 
            url = format_url % name.lower() 
            manager.load(url) 
    app.exec_() 
    for url, html in manager.results: 
        print(url) 
        print(html)