Qt多线程-豆瓣机器人(二)

这一篇聊一下整个pyqt5后台架构的设计,下图是一个最简单的项目框架

  • ui_mainwindow.py ----ui文件
  • my_thread.py ----多线程爬虫文件
  • spider.py ----爬虫文件入口
  • main.py ----项目文件

ui_mainwindow.py

UI文件中有一个大类,两个函数,一个函数是初始化元素,第二个是初始化元素的值

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

# Form implementation generated from reading ui file 'douban_ui.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(989, 1438)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.comboBox_head = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox_head.setObjectName("comboBox_head")
        self.comboBox_head.addItem("")
        self.comboBox_head.addItem("")
        self.gridLayout.addWidget(self.comboBox_head, 0, 1, 1, 1)
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setObjectName("pushButton")
        ..........
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.comboBox_head.setItemText(0, _translate("MainWindow", "有头浏览"))
        self.comboBox_head.setItemText(1, _translate("MainWindow", "无头浏览"))
        self.pushButton.setText(_translate("MainWindow", "开始"))
        self.label_7.setText(_translate("MainWindow", "是否显示浏览器"))
        ......
        self.label.setText(_translate("MainWindow", "黑名单"))
        self.menu_v1.setTitle(_translate("MainWindow", "豆瓣自动评论v1"))
        self.menu.setTitle(_translate("MainWindow", "帮助"))


spider.py 爬虫程序入口


from ui_mainwindow import *
from PyQt5.QtWidgets import QMainWindow, QFileDialog
from my_thread import WorkThread


# 继承UI文件的类
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        # 在这里是setupUI
        self.setupUi(self)
        self.pushButton.clicked.connect(self.run_spider)
        self.pushButton_loadexcel.clicked.connect(self.read_file)

    def read_file(self):
        directory1 = QFileDialog.getOpenFileName(None, "选择文件", "/home")[0]
        self.lineEdit_excel.setText(directory1)

    def run_spider(self):
        self.textBrowser_display.append('------------开始------------')
        # 通常提取界面的数据可以输用text()
        username = self.lineEdit_username.text()
        password = self.lineEdit_password.text()
        url = self.lineEdit_movieurl.text()
        comment = self.textEdit_comment.toPlainText()
        header = self.comboBox_head.currentText()
        random_target = self.comboBox_random_target.currentText()
        star = self.comboBox_star.currentText()
        time = self.lineEdit_time.text()
        excel = self.lineEdit_excel.text()
        blacklist = self.lineEdit_blacklist.text()
        # 这里是关键,需要将参数传给多线程的程序
        self.th = WorkThread(username, password, url, comment, header, random_target, star, time, excel, blacklist)

        self.pushButton.setChecked(True)
        self.pushButton.setDisabled(True)

        # 将线程th的信号finishSignal和UI主线程中的槽函数button_finish进行连接
        self.th.finishSignal.connect(self.end_spider)
        self.th.displaySignal.connect(self.display)
        # 启动线程
        self.th.start()

    def display(self, target_str):
        self.textBrowser_display.append(target_str)

    def end_spider(self):
        self.textBrowser_display.append('------------结束------------')
        # 设置按钮可用
        self.pushButton.setChecked(False)
        self.pushButton.setDisabled(False)


要点:

  • 继承ui文件,与前端分离,并启动setupUI
  • 通过传递参数到th实现数据传输
  • self.th.finishSignal.connect(self.end_spider) 传递结束信号
  • self.th.displaySignal.connect(self.display) 传递展示信号
  • self.th.start() 启动线程!!!!

其实这个模块说通俗一点可以理解为是前端ui文件的衍生,主要是为了代码可读性把这部分分离出来,其实都写在ui文件里也可以。

其次就是信号传递这个点,我个人认为是pyqt5实现多线程的关键,他的作用就是一个触发器,如果后端程序运行到这个信号时,会将参数传给前端,比如说展示数据,展示内容等。如果不加这个,纯单线程运行的话,会感觉exe特别卡顿。

欢迎技术探讨