硒不响应的PyQT5应用-任务完成前不显示进度栏,也不在控制台中发送文本

时间:2019-03-22 22:08:35

标签: python python-3.x selenium-webdriver pyqt pyqt5

enter image description here

使用PyQt5和硒时,窗口标题显示为“无响应”。 脚本执行完成后,将显示进度条和控制台发射流。需要帮助以解决此问题。

 from selenium import webdriver
 from selenium.common.exceptions import 
  TimeoutException,NoSuchElementException,ElementClickInterceptedException
 from selenium.webdriver.support.ui import WebDriverWait,Select
 from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.common.by import By
 from selenium.webdriver.firefox.options import Options
 from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
 from selenium.webdriver.common.action_chains import ActionChains
 import time
 import os.path
 import pandas as pd
 import csv
 import threading
 from PyQt5 import QtCore, QtGui, QtWidgets

 class EmittingStream(QtCore.QObject):

textWritten = QtCore.pyqtSignal(str)
def write(self, text):
    self.textWritten.emit(str(text))

 class Ui_Fuse(object):

def launch_Selenium_Thread(self):
    _translate = QtCore.QCoreApplication.translate
    self.pushButton.setEnabled(False)
    self.progressBar.setValue(0)
    self.textEdit.clear()
    t = threading.Thread(target=self.generate())
    t.start()

def loaddata(self):
    self.completed = 0
    while self.completed < 100:
        self.completed += 0.0001
        self.progressBar.setValue(self.completed)

def setupUi(self, Fuse):
    Fuse.setObjectName("Fuse")
    Fuse.resize(513, 284)
    font = QtGui.QFont()
    font.setPointSize(10)
    font.setBold(True)
    font.setWeight(75)
    Fuse.setFont(font)
    self.label = QtWidgets.QLabel(Fuse)
    self.label.setGeometry(QtCore.QRect(90, 67, 71, 20))
    self.label.setObjectName("label")
    self.LineEdit = QtWidgets.QLineEdit(Fuse)
    self.LineEdit.setGeometry(QtCore.QRect(170, 60, 181, 31))
    self.LineEdit.setObjectName("textEdit")
    self.LineEdit_2 = QtWidgets.QLineEdit(Fuse)
    self.LineEdit_2.setGeometry(QtCore.QRect(170, 100, 181, 31))
    self.LineEdit_2.setObjectName("textEdit_2")
    self.LineEdit_2.setEchoMode(QtWidgets.QLineEdit.Password)
    self.pushButton = QtWidgets.QPushButton(Fuse)
    self.pushButton.setGeometry(QtCore.QRect(169, 150, 90, 31))
    self.pushButton.setObjectName("pushButton")
    self.pushButton.clicked.connect(self.launch_Selenium_Thread)
    self.pushButton.clicked.connect(self.loaddata)
    self.pushButton_2 = QtWidgets.QPushButton(Fuse)
    self.pushButton_2.setGeometry(QtCore.QRect(262, 150, 90, 31))
    self.pushButton_2.setObjectName("pushButton_3")
    self.pushButton_2.clicked.connect(self.clearall)
    self.label_2 = QtWidgets.QLabel(Fuse)
    self.label_2.setGeometry(QtCore.QRect(89, 107, 71, 20))
    self.label_2.setObjectName("label_2")
    self.label_3 = QtWidgets.QLabel(Fuse)
    self.label_3.setGeometry(QtCore.QRect(180, 127, 181, 30))
    self.label_3.setObjectName("label_3")
    self.progressBar = QtWidgets.QProgressBar(Fuse)
    self.progressBar.setEnabled(True)
    self.progressBar.setGeometry(QtCore.QRect(8, 270, 506, 10))
    self.progressBar.setLayoutDirection(QtCore.Qt.LeftToRight)
    self.progressBar.setAutoFillBackground(False)
    self.progressBar.setProperty("value", 24)
    self.progressBar.setAlignment(QtCore.Qt.AlignJustify)
    self.progressBar.setInvertedAppearance(False)
    self.progressBar.setObjectName("progressBar")
    self.textEdit = QtWidgets.QTextEdit(Fuse)
    self.textEdit.setGeometry(QtCore.QRect(8, 200, 497, 60))
    self.textEdit.setObjectName("textEdit")
    self.textEdit.setFont(font)
    self.textEdit.setReadOnly(True)

    self.retranslateUi(Fuse)
    QtCore.QMetaObject.connectSlotsByName(Fuse)

def retranslateUi(self, Fuse):
    _translate = QtCore.QCoreApplication.translate
    Fuse.setWindowTitle(_translate("Fuse", "Fuse | Invoice Generation"))
    self.label.setText(_translate("Fuse", "<html><head/><body><p><span style=\" font-size:10pt; font-weight:600;\">User Name</span></p></body></html>"))
    self.pushButton.setText(_translate("Fuse", "Submit"))
    self.pushButton_2.setText(_translate("Fuse", "Reset"))
    self.label_2.setText(_translate("Fuse", "<html><head/><body><p><span style=\" font-size:10pt; font-weight:600;\">Password</span></p></body></html>"))
    self.label_3.setText(_translate("Fuse", "<html><head/><body><p><span style=\" font-size:7pt; color:red; font-weight:600;\">Invalid User Name or Password</span></p></body></html>"))
    self.label_3.hide()
    Fuse.setWindowFlags( QtCore.Qt.CustomizeWindowHint | QtCore.Qt.MSWindowsFixedSizeDialogHint |QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint )

def clearall(self):
    self.LineEdit.clear()
    self.LineEdit_2.clear()
    self.label_3.clear()
    self.textEdit.clear()
    self.LineEdit.setEnabled(True)
    self.LineEdit_2.setEnabled(True)
    self.pushButton.setEnabled(True)

def __init__(self, parent=None, **kwargs):
    sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
    sys.stderr = EmittingStream(textWritten=self.normalOutputWritten)

def __del__(self):
    sys.stdout = sys.__stdout__
    sys.stderr = sys.__stderr__

def normalOutputWritten(self, text):
    cursor = self.textEdit.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.textEdit.setTextCursor(cursor)
    self.textEdit.ensureCursorVisible()

def generate(self):
    self.LineEdit.setEnabled(False)
    self.LineEdit_2.setEnabled(False)
    self.pushButton.setEnabled(False)
    self.textEdit.clear()
    options = Options()
    options.add_argument("--headless")
    profile = FirefoxProfile()
    driver = webdriver.Firefox(firefox_profile=profile,firefox_options=options,executable_path= os.path.expandvars('%userprofile%\\Desktop\\RPA\\Tools\\geckodriver.exe'))
    driver.get("https://example.com/Login.aspx")
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.ID, "loginBtnn")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')
    search_field = driver.find_element_by_id("txtUserName")
    search_field.clear()
    username = self.LineEdit.text()
    search_field.send_keys(username)
    search_field = driver.find_element_by_id("txtPassword")
    search_field.clear()
    password = self.LineEdit_2.text()
    search_field.send_keys(password)
    time.sleep(5)
    driver.find_element_by_id("BtnLogin").click()
    self.textEdit.insertPlainText('Clicked on Login')
    time.sleep(5)
    try:
        element = driver.find_element_by_xpath("//span[contains(@id,'lblFailure')]")
        if element.text == "Invalid User Name or Password":
            self.textEdit.insertPlainText("Invalid User Name or Password")
            self.label_3.show()
            self.LineEdit.setEnabled(True)
            self.LineEdit_2.setEnabled(True)
            self.pushButton.setEnabled(True)
            driver.quit()
            driver.close()
    except NoSuchElementException:
        self.textEdit.insertPlainText("Correct User Name or Password")
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.XPATH, "/html/body/form/div[4]/a/img")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')    
    driver.find_element_by_xpath("/html/body/form/div[4]/a/img").click()
    self.textEdit.insertPlainText('Clicked Product Links')
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.ID, "lnkFuse")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')   
    driver.find_element_by_id("lnkFuse").click()
    self.textEdit.insertPlainText('Clicked on Fuse Link')
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.XPATH, "//span[@class='Invoice Processing'][contains(.,'Invoice Processing')]")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')
    element_to_hover_over = driver.find_element_by_xpath("//span[@class='Invoice Processing'][contains(.,'Invoice Processing')]")
    hover = ActionChains(driver).move_to_element(element_to_hover_over)
    hover.perform()
    self.textEdit.insertPlainText('Clicked on Invoice Processing')
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.XPATH, "//a[@href='../../RS/Batch/AuditInvoice.aspx']")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')
    driver.find_element_by_xpath("//a[@href='../../RS/Batch/AuditInvoice.aspx']").click()
    self.textEdit.insertPlainText('Clicked on Audit Invoices')
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.ID, "MainContent_ddlSearchInvoiceStatus")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')
    invoice_audit = 'Audited' 
    InvoiceStatus = Select(driver.find_element_by_id("MainContent_ddlSearchInvoiceStatus"))
    for option in InvoiceStatus.options:
        option_text = option.text
        if invoice_audit in option_text:
            option.click()
            break
    self.textEdit.insertPlainText('Selected Audited from Dropdown')
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.ID, "MainContent_btnSearch")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')
    driver.find_element_by_id('MainContent_btnSearch').click() 
    self.textEdit.insertPlainText('Clicked on Search Button')
    try:
        WebDriverWait(driver, 60000).until(
        EC.element_to_be_clickable((By.ID, "MainContent_ddlItemsPerPage")));
    except TimeoutException:
        self.textEdit.insertPlainText('Timed out waiting for page to load')    
    element = driver.find_element_by_id('MainContent_ddlItemsPerPage')
    element.location_once_scrolled_into_view
    driver.find_element_by_id('MainContent_ddlItemsPerPage').click() 
    items_perpage = '500' 
    records_list = Select(driver.find_element_by_id("MainContent_ddlItemsPerPage"))
    for option in records_list.options:
        option_text = option.text
        if items_perpage in option_text:
            option.click()
            break
    time.sleep(5)
    self.textEdit.insertPlainText('Selected Max items per page')

    list_links = driver.find_elements_by_partial_link_text('Generate')
    time.sleep(5)
    id_list = []
    for i in list_links:
        data = i.get_attribute('id')
        self.textEdit.insertPlainText(data)
        id_list.append(data)
        id_df = pd.DataFrame(id_list)
        self.textEdit.insertPlainText(id_df)
    for row in id_df.values:
        row_val = str(row)[2:-2]
        try:
            WebDriverWait(driver, 60000).until(
            EC.element_to_be_clickable((By.ID, "MainContent_gvAuditInvoice")));
            self.textEdit.insertPlainText('Element Found')               
            element = driver.find_element_by_id(row_val)
            element.location_once_scrolled_into_view
            WebDriverWait(driver, 60000).until(
            EC.element_to_be_clickable((By.ID, row_val)));
            driver.find_element_by_id(row_val).click()
            localtime = time.strftime("%m-%d-%Y  %I:%M:%S")
            self.textEdit.insertPlainText(row_val + "|" + 'Clicked' + '|' + localtime)
            time.sleep(5)
        except ElementClickInterceptedException:
            continue
            self.textEdit.insertPlainText('Timed out waiting for page to load')
        time.sleep(5)
    self.textEdit.insertPlainText('Completed')
    self.LineEdit.clear()
    self.LineEdit_2.clear()
    self.label_3.clear()
    self.LineEdit.setEnabled(True)
    self.LineEdit_2.setEnabled(True)
    self.pushButton.setEnabled(True)
    self.stop_Selenium_Thread()

def stop_Selenium_Thread(self):
    _translate = QtCore.QCoreApplication.translate
    self.pushButton.setEnabled(True)
    t = threading.Thread(target=self.stop_Selenium_Thread)
    for i, t in enumerate(self.generate()):
        t.join()
        print('Thread {} Stopped'.format(i))


if __name__ == "__main__":
   import sys
   app = QtWidgets.QApplication(sys.argv)
   Fuse = QtWidgets.QDialog()
   ui = Ui_Fuse()
   ui.setupUi(Fuse)
   Fuse.show()
   sys.exit(app.exec_())

我的实际结果应该是当我按下应用程序上的“提交”按钮时,程序应该开始执行脚本,并且代码中给出的self.textEdit.insertPlainText应该随着进度条移动而流进文本编辑中。

1 个答案:

答案 0 :(得分:1)

首先,您有以下不良编程习惯:

  • 您正在用GUI弄乱业务逻辑。
  • 变量名称未描述变量的用途。
  • 文件中有很多代码。

另一方面,转到Qt,您会遇到以下错误:

  • 您不应该从另一个线程修改GUI,因为GUI并非安全的,您必须使用信号,事件等。
  • 更改大小时,必须使用GUI的布局来适应。

另一方面,我尚未测试您的代码,但我发现您的错误之一是

t = threading.Thread(target=self.generate())

由于您要调用函数而不是将其传递给函数,因此它必须是

t = threading.Thread(target=self.generate)

考虑到上述情况,我实现了以下内容:

fuse_ui.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'fuse.ui'
#
# Created by: PyQt5 UI code generator 5.12.1
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Fuse(object):
    def setupUi(self, Fuse):
        Fuse.setObjectName("Fuse")
        Fuse.resize(556, 513)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(Fuse.sizePolicy().hasHeightForWidth())
        Fuse.setSizePolicy(sizePolicy)
        self.verticalLayout = QtWidgets.QVBoxLayout(Fuse)
        self.verticalLayout.setObjectName("verticalLayout")
        spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.verticalLayout.addItem(spacerItem)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem1 = QtWidgets.QSpacerItem(80, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.userNameLabel = QtWidgets.QLabel(Fuse)
        self.userNameLabel.setObjectName("userNameLabel")
        self.gridLayout.addWidget(self.userNameLabel, 0, 0, 1, 1)
        self.userNameLineEdit = QtWidgets.QLineEdit(Fuse)
        self.userNameLineEdit.setObjectName("userNameLineEdit")
        self.gridLayout.addWidget(self.userNameLineEdit, 0, 1, 1, 1)
        self.passwordLabel = QtWidgets.QLabel(Fuse)
        self.passwordLabel.setObjectName("passwordLabel")
        self.gridLayout.addWidget(self.passwordLabel, 1, 0, 1, 1)
        self.passwordLineEdit = QtWidgets.QLineEdit(Fuse)
        self.passwordLineEdit.setObjectName("passwordLineEdit")
        self.gridLayout.addWidget(self.passwordLineEdit, 1, 1, 1, 1)
        self.invalidLabel = QtWidgets.QLabel(Fuse)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.invalidLabel.sizePolicy().hasHeightForWidth())
        self.invalidLabel.setSizePolicy(sizePolicy)
        self.invalidLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.invalidLabel.setObjectName("invalidLabel")
        self.gridLayout.addWidget(self.invalidLabel, 2, 1, 1, 1)
        self.widget = QtWidgets.QWidget(Fuse)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
        self.widget.setSizePolicy(sizePolicy)
        self.widget.setObjectName("widget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.submitButton = QtWidgets.QPushButton(self.widget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.submitButton.sizePolicy().hasHeightForWidth())
        self.submitButton.setSizePolicy(sizePolicy)
        self.submitButton.setObjectName("submitButton")
        self.horizontalLayout.addWidget(self.submitButton)
        self.resetButton = QtWidgets.QPushButton(self.widget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.resetButton.sizePolicy().hasHeightForWidth())
        self.resetButton.setSizePolicy(sizePolicy)
        self.resetButton.setObjectName("resetButton")
        self.horizontalLayout.addWidget(self.resetButton)
        self.gridLayout.addWidget(self.widget, 3, 1, 1, 1)
        self.horizontalLayout_2.addLayout(self.gridLayout)
        spacerItem2 = QtWidgets.QSpacerItem(80, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem2)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        spacerItem3 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.verticalLayout.addItem(spacerItem3)
        self.logTextEdit = QtWidgets.QTextEdit(Fuse)
        self.logTextEdit.setObjectName("logTextEdit")
        self.verticalLayout.addWidget(self.logTextEdit)
        self.progressBar = QtWidgets.QProgressBar(Fuse)
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.verticalLayout.addWidget(self.progressBar)

        self.retranslateUi(Fuse)
        QtCore.QMetaObject.connectSlotsByName(Fuse)

    def retranslateUi(self, Fuse):
        _translate = QtCore.QCoreApplication.translate
        Fuse.setWindowTitle(_translate("Fuse", "Dialog"))
        self.userNameLabel.setText(_translate("Fuse", "<html><head/><body><p><span style=\" font-weight:600;\">User Name</span></p></body></html>"))
        self.passwordLabel.setText(_translate("Fuse", "<html><head/><body><p><span style=\" font-weight:600;\">Password</span></p></body></html>"))
        self.invalidLabel.setText(_translate("Fuse", "<html><head/><body><p><span style=\" font-size:7pt; color:red; font-weight:600;\">Invalid User Name or Password</span></p></body></html>"))
        self.submitButton.setText(_translate("Fuse", "Submit"))
        self.resetButton.setText(_translate("Fuse", "Reset"))




if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Fuse = QtWidgets.QDialog()
    ui = Ui_Fuse()
    ui.setupUi(Fuse)
    Fuse.show()
    sys.exit(app.exec_())

fusi_worker.py

import os
import time

from selenium import webdriver
from selenium.common.exceptions import TimeoutException,NoSuchElementException,ElementClickInterceptedException
from selenium.webdriver.support.ui import WebDriverWait,Select
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
from selenium.webdriver.common.action_chains import ActionChains

from PyQt5 import QtCore

import pandas as pd

class FusiWorker(QtCore.QObject):
    progressChanged = QtCore.pyqtSignal(int)
    logSignal = QtCore.pyqtSignal(str)
    invalidSignal = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()

    @QtCore.pyqtSlot(str, str)
    def start(self, username, password):

        options = Options()
        options.add_argument("--headless")
        profile = FirefoxProfile()
        driver_path = os.path.expandvars('%userprofile%\\Desktop\\RPA\\Tools\\geckodriver.exe')
        driver = webdriver.Firefox(firefox_profile=profile, options=options, executable_path=driver_path)
        driver.get("https://example.com/Login.aspx")
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, "loginBtnn")));
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')

        search_field = driver.find_element_by_id("txtUserName")
        search_field.clear()
        search_field.send_keys(password)
        time.sleep(5)
        driver.find_element_by_id("BtnLogin").click()
        self.logSignal.emit('Clicked on Login')
        time.sleep(5)
        try:
            element = driver.find_element_by_xpath("//span[contains(@id,'lblFailure')]")
            if element.text == "Invalid User Name or Password":
                self.logSignal.emit("Invalid User Name or Password")
                self.invalidSignal.emit()
                driver.quit()
                driver.close()
        except NoSuchElementException:
            self.logSignal.emit("Correct User Name or Password")
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.XPATH, "/html/body/form/div[4]/a/img")));
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')    
        driver.find_element_by_xpath("/html/body/form/div[4]/a/img").click()
        self.logSignal('Clicked Product Links')
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, "lnkFuse")));
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')
        driver.find_element_by_id("lnkFuse").click()
        self.logSignal.emit('Clicked on Fuse Link')
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.XPATH, "//span[@class='Invoice Processing'][contains(.,'Invoice Processing')]")));
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')
        element_to_hover_over = driver.find_element_by_xpath("//span[@class='Invoice Processing'][contains(.,'Invoice Processing')]")
        hover = ActionChains(driver).move_to_element(element_to_hover_over)
        hover.perform()
        self.logSignal.emit('Clicked on Invoice Processing')
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.XPATH, "//a[@href='../../RS/Batch/AuditInvoice.aspx']")))
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')
        driver.find_element_by_xpath("//a[@href='../../RS/Batch/AuditInvoice.aspx']").click()
        self.logSignal.emit('Clicked on Audit Invoices')
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, "MainContent_ddlSearchInvoiceStatus")))
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')
        invoice_audit = 'Audited' 
        InvoiceStatus = Select(driver.find_element_by_id("MainContent_ddlSearchInvoiceStatus"))
        for option in InvoiceStatus.options:
            option_text = option.text
            if invoice_audit in option_text:
                option.click()
                break
        self.logSignal.emit('Selected Audited from Dropdown')
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, "MainContent_btnSearch")))
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')
        driver.find_element_by_id('MainContent_btnSearch').click() 
        self.logSignal.emit('Clicked on Search Button')
        try:
            WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, "MainContent_ddlItemsPerPage")))
        except TimeoutException:
            self.logSignal.emit('Timed out waiting for page to load')
        element = driver.find_element_by_id('MainContent_ddlItemsPerPage')
        element.location_once_scrolled_into_view
        driver.find_element_by_id('MainContent_ddlItemsPerPage').click() 
        items_perpage = '500' 
        records_list = Select(driver.find_element_by_id("MainContent_ddlItemsPerPage"))
        for option in records_list.options:
            option_text = option.text
            if items_perpage in option_text:
                option.click()
                break
        time.sleep(5)
        self.logSignal.emit('Selected Max items per page')
        list_links = driver.find_elements_by_partial_link_text('Generate')
        time.sleep(5)
        id_list = []
        for i in list_links:
            data = i.get_attribute('id')
            self.logSignal.emit(data)
            id_list.append(data)
            # TODO
            id_df = pd.DataFrame(id_list)
            self.logSignal.emit(id_df.to_string())
        for row in id_df.values:
            row_val = str(row)[2:-2]
            try:
                WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, "MainContent_gvAuditInvoice")))
                self.logSignal.emit('Element Found')
                element = driver.find_element_by_id(row_val)
                element.location_once_scrolled_into_view
                WebDriverWait(driver, 60000).until(EC.element_to_be_clickable((By.ID, row_val)))
                driver.find_element_by_id(row_val).click()
                localtime = time.strftime("%m-%d-%Y  %I:%M:%S")
                self.logSignal.emit(row_val + "|" + 'Clicked' + '|' + localtime)
                time.sleep(5)
            except ElementClickInterceptedException:
                continue
                self.logSignal.emit('Timed out waiting for page to load')
            time.sleep(5)
        self.logSignal.emit('Completed')
        self.finished.emit()

    @QtCore.pyqtSlot()
    def load_data(self):
        completed = 0
        while completed < 100:
            completed += 0.0001
            self.progressChanged.emit(completed)
            time.sleep(0.01)

main.py

import threading
from PyQt5 import QtCore, QtGui, QtWidgets

from fuse_worker import FusiWorker
from fuse_ui import Ui_Fuse

class Fuse(QtWidgets.QDialog, Ui_Fuse):
    def __init__(self, parent=None):
        super(Fuse, self).__init__(parent)
        self.setupUi(self)
        self.setWindowFlags(QtCore.Qt.CustomizeWindowHint | 
                             QtCore.Qt.MSWindowsFixedSizeDialogHint |
                             QtCore.Qt.WindowCloseButtonHint | 
                             QtCore.Qt.WindowMinimizeButtonHint)
        self.init()
        self.connections()

    def init(self):
        self._worker = FusiWorker()
        self.reset()
        thread = QtCore.QThread(self)
        thread.start()
        self._worker.moveToThread(thread)
        self.progressBar.setValue(0)

    def connections(self):
        self.submitButton.clicked.connect(self.submit)
        self.resetButton.clicked.connect(self.reset)
        self._worker.logSignal.connect(self.logTextEdit.insertPlainText)
        self._worker.invalidSignal.connect(self.invalidate)
        self._worker.finished.connect(self.reset)
        self._worker.progressChanged.connect(self.progressBar.setValue)
        self.progressBar.setValue(0)

    @QtCore.pyqtSlot()
    def submit(self):
        username = self.userNameLineEdit.text()
        password = self.passwordLineEdit.text()
        self.logTextEdit.clear()
        self.userNameLineEdit.setEnabled(False)
        self.passwordLineEdit.setEnabled(False)
        threading.Thread(target=self._worker.start, args=(username, password,), daemon=True).start()
        threading.Thread(target=self._worker.load_data, daemon=True).start()

    @QtCore.pyqtSlot()
    def reset(self):
         self.userNameLineEdit.clear()
         self.passwordLineEdit.clear()
         self.invalidLabel.hide()
         self.userNameLineEdit.setEnabled(True)
         self.passwordLineEdit.setEnabled(True)
         self.submitButton.setEnabled(True)

    @QtCore.pyqtSlot()
    def invalidate(self):
        self.invalidLabel.show()
        self.reset()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Fuse()
    w.show()
    sys.exit(app.exec_())

这些文件必须位于同一文件夹中

├── fuse_ui.py
├── fuse_worker.py
└── main.py