Прежде всего у вас есть следующие плохие практики программирования:
- Вы путаете бизнес-логику с графическим интерфейсом.
- Имена переменных не описывают использование переменных.
- Много кода в файле.
С другой стороны, при переходе на Qt у вас есть следующие ошибки:
- Вы не должны изменять 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