Загрузка анимации с проблемой зависания PyQt5 в процессе веб-автоматизации с помощью Selenium

Я работал над несколькими проектами веб-автоматизации. В этом примере я сократил свой код до открытия некоторых URL-адресов. Я хочу добавить удобный интерфейс, пока продолжался основной процесс. Однако, когда я хочу показать пользователю загрузку gif, он просто зависает из-за процесса селена. Если процесс селена завершен, время отдыха gif продолжается. Например, моя загрузка gif установлена ​​на 20 секунд. Процесс селена занял 5 секунд. Итак, в течение 5 секунд мой загружаемый gif зависает, затем процесс селена завершается и закрывается, анимация загрузки продолжается 14 секунд.

Также есть способ сделать это с наложением. Я искал несколько примеров и пробовал, но это не сработало

import sys
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class LoadingScreen(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(200,200)
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.CustomizeWindowHint)

        self.label_animation = QLabel(self)
        self.movie = QMovie("loading.gif")
        self.label_animation.setMovie(self.movie)

        timer = QTimer(self)
        self.startAnimation()
        timer.singleShot(20000, self.stopAnimation)

        self.show()

    def startAnimation(self):
        self.movie.start()

    def stopAnimation(self):
        self.movie.stop()
        self.close()

class demo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Loading Overlay with Selenium Problem")
        self.resize(500, 500)
        self.center()
        self.twitter_icon = QtWidgets.QLabel("")
        self.twitter_icon.setAlignment(Qt.AlignCenter)
        self.pixmap = QtGui.QPixmap("twitter.png")
        self.pixmap = self.pixmap.scaled(64, 64, Qt.KeepAspectRatio, Qt.FastTransformation)
        self.twitter_icon.setPixmap(self.pixmap)
        self.twt_btn = QtWidgets.QPushButton("Twitter")

        v_box = QtWidgets.QVBoxLayout()
        v_box.addStretch()
        v_box.addWidget(self.twitter_icon)
        v_box.addWidget(self.twt_btn)
        v_box.addStretch()

        self.setLayout(v_box)

        self.twt_btn.clicked.connect(self.clkdBtn)
        self.show()

    def clkdBtn(self):
        self.hide()
        self.loading = LoadingScreen()
        browser = webdriver.Chrome()
        browser.get("https://twitter.com/login")
        time.sleep(1)
        #do more stuff in project instead i add more url
        browser.get("https://twitter.com/explore")
        time.sleep(1)
        browser.get("https://twitter.com/login")
        time.sleep(1)
        browser.close()
        time.sleep(1)
        self.show()

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

app = QApplication(sys.argv)
dm = demo()
app.exit((app.exec_()))

1 ответ

Решение

Вы не должны реализовывать трудоемкие задачи (selenium и time.sleep()) в основном потоке, поскольку они блокируют графический интерфейс, поэтому вы должны запустить эту часть в другом потоке и уведомить графический интерфейс с помощью сигналов для изменения его состояния (показать или скрыть окна)

import sys
import threading
import time

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

from PyQt5 import QtWidgets, QtGui, QtCore


class SeleniumManager(QtCore.QObject):
    started = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()

    def start(self):
        threading.Thread(target=self._execute, daemon=True).start()

    def _execute(self):
        self.started.emit()
        browser = webdriver.Chrome()
        browser.get("https://twitter.com/login")
        time.sleep(1)
        # do more stuff in project instead i add more url
        browser.get("https://twitter.com/explore")
        time.sleep(1)
        browser.get("https://twitter.com/login")
        time.sleep(1)
        browser.close()
        time.sleep(1)
        self.finished.emit()


class LoadingScreen(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(200, 200)
        self.setWindowFlags(
            QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.CustomizeWindowHint
        )

        self.label_animation = QtWidgets.QLabel(self)
        self.movie = QtGui.QMovie("loading.gif")
        self.label_animation.setMovie(self.movie)

    def startAnimation(self):
        self.movie.start()
        self.show()
        QtCore.QTimer.singleShot(2 * 1000, self.stopAnimation)

    def stopAnimation(self):
        self.movie.stop()
        self.hide()


class Demo(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Loading Overlay with Selenium Problem")
        self.resize(500, 500)
        self.center()
        self.twitter_icon = QtWidgets.QLabel("")
        self.twitter_icon.setAlignment(QtCore.Qt.AlignCenter)
        self.pixmap = QtGui.QPixmap("twitter.png")
        self.pixmap = self.pixmap.scaled(
            64, 64, QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation
        )
        self.twitter_icon.setPixmap(self.pixmap)
        self.twt_btn = QtWidgets.QPushButton("Twitter")

        v_box = QtWidgets.QVBoxLayout(self)
        v_box.addStretch()
        v_box.addWidget(self.twitter_icon)
        v_box.addWidget(self.twt_btn)
        v_box.addStretch()

        self.loading = LoadingScreen()
        self._manager = SeleniumManager()

        self._manager.started.connect(self.loading.startAnimation)
        self._manager.finished.connect(self.loading.stopAnimation)
        self.twt_btn.clicked.connect(self._manager.start)
        self._manager.started.connect(self.hide)
        self._manager.finished.connect(self.show)

    def center(self):
        qr = self.frameGeometry()
        cp = QtWidgets.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())


if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    dm = Demo()
    dm.show()
    app.exit((app.exec_()))
Другие вопросы по тегам