【问题标题】:GUI become unresponsive while looping循环时 GUI 变得无响应
【发布时间】:2019-12-03 03:07:10
【问题描述】:

单击按钮后,表单将无响应,直到解析函数完成工作。

我想将 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】:

您必须在另一个线程中执行繁重的任务(请求 + 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_())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多