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

标签 python multithreading web-scraping pyqt qwebengineview

我正在尝试使用 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)

关于python - 为什么我的 PyQt 代码在多线程时不能完全执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57221092/

相关文章:

Java 套接字 : No buffer space available (maximum connections reached? )

c# - .NET 线程问题

python - 将表数据抓取到 .csv 中

python - 使用 BeautifulSoup 在网页上查找特定文本

python - 嵌套命名元组

python - pip 是否可以从 setup.cfg 安装,就像从需求文件安装一样?

c++ - 带互斥量的多线程输入不平滑(如预期)

web-scraping - 如何以编程方式访问 Wayback Machine?

python - 函数定义中带星号的变量的默认初始化

python xlutils : formatting_info=True not yet implemented