GUI循环时无响应

问题描述 投票:1回答:1

我单击按钮后,表单将变得无响应,直到解析功能完成其工作。

我想将searchAll函数移至线程。我确实读过一些类似问题的答案,但我不知道如何。

class MyForm(QDialog):


    def __init__(self):
        super().__init__()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.ui.buttonOK.clicked.connect(self.searchAll)
        self.show()

    def searchAll(self):

        sID = self.ui.txtSellerID.text()
        sUrl = "https://removed.com/" + sID + "/p/?section=2&page=1"
        sr = requests.get(sUrl)
        soup1 = BeautifulSoup(sr.text, "html.parser")

        NumberOfPagesBlock = soup1.find_all("li", class_="text-gray")

        if not NumberOfPagesBlock:
            QMessageBox.about(self, "Warning", "Nothing Here")
        else:
            items = re.compile(r'[^\d.]+')
            PagesCount = -(-items // 60)

            for i in range(1, int(PagesCount + 1)):
                itemsIdDs = soup1.find_all("div", class_="large-single-item")

                for itemsIdD in itemsIdDs:
                    iUrl = ("https://removed.com/" + itemsIdDs.get('data-ean') + "/s")
                    r = requests.get(iUrl)
                    soup = BeautifulSoup(r.text, "html.parser")
                    seller = soup.find("div", id="productTrackingParams")
                    title = (str(ctr) + '- ' + "Title " + str(seller.get('data-title')))
                    self.ui.txtDetails.appendPlainText(title)


if __name__ == "__main__":

    app = QApplication(sys.argv)
    w = MyForm()
    w.show()
    sys.exit(app.exec_())
python pyqt pyqt5 qthread
1个回答
1
投票

您必须在另一个线程中执行繁重的任务(请求+ BeautifulSoup),因为它们阻塞了GUI所在的主线程,从而阻止了GUI的正常工作,而这例如通过冻结屏幕来体现。在这种情况下,我将实现一个工作线程方法:

import re
import ssl
import sys
from functools import partial

import requests
from PyQt5.QtCore import QObject, QThread, QTimer, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from bs4 import BeautifulSoup

from foo_module import Ui_Dialog


class ScrapeWorker(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    resultsChanged = pyqtSignal(str)
    errorSignal = pyqtSignal(str)

    @pyqtSlot(str)
    def run(self, text):
        self.started.emit()
        sUrl = "https://removed.com/{}/p/?section=2&page=1".format(text)
        try:
            sr = requests.get(sUrl)
        except Exception as e:
            self.errorSignal.emit("error: {}".format(e))
            self.finished.emit()
            return
        soup1 = BeautifulSoup(sr.text, "html.parser")
        NumberOfPagesBlock = soup1.find_all("li", class_="text-gray")
        if not NumberOfPagesBlock:
            self.errorSignal.emit("Nothing Here")
        else:
            items = re.compile(r"[^\d.]+")
            PagesCount = -(-items // 60)
            for i in range(1, int(PagesCount + 1)):
                itemsIdDs = soup1.find_all("div", class_="large-single-item")

                for itemsIdD in itemsIdDs:
                    iUrl = "https://removed.com/{}/s".format(itemsIdDs.get("data-ean"))
                    r = requests.get(iUrl)
                    soup = BeautifulSoup(r.text, "html.parser")
                    seller = soup.find("div", id="productTrackingParams")
                    title = "{}- Title {}".format(ctr, seller.get("data-title"))
                    self.resultsChanged.emit(title)
        self.finished.emit()


class MyForm(QDialog):
    def __init__(self):
        super().__init__()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.ui.buttonOK.clicked.connect(self.searchAll)

        thread = QThread(self)
        thread.start()

        self.m_worker = ScrapeWorker()
        self.m_worker.moveToThread(thread)
        self.m_worker.started.connect(self.onStarted)
        self.m_worker.finished.connect(self.onFinished)
        self.m_worker.resultsChanged.connect(self.onResultChanged)
        self.m_worker.errorSignal.connect(self.onErrorSignal)

    @pyqtSlot()
    def searchAll(self):
        sID = self.ui.txtSellerID.text()
        wrapper = partial(self.m_worker.run, sID)
        QTimer.singleShot(0, wrapper)

    @pyqtSlot(str)
    def onResultChanged(self, title):
        self.ui.txtDetails.appendPlainText(title)

    @pyqtSlot()
    def onStarted(self):
        self.ui.buttonOK.setEnabled(False)

    @pyqtSlot()
    def onFinished(self):
        self.ui.buttonOK.setEnabled(True)

    @pyqtSlot(str)
    def onErrorSignal(self, message):
        QMessageBox.about(self, "Warning", message)


if __name__ == "__main__":

    app = QApplication(sys.argv)
    w = MyForm()
    w.show()
    sys.exit(app.exec_())
© www.soinside.com 2019 - 2024. All rights reserved.