简体   繁体   中英

Function returning itself instead of str value

I am using PyQt5 in conjunction with cfscrape and BeautifulSoup in an attempt to display the baby name of the day as a label. However, the function I am using to grab and return the baby name is returning itself instead of the name. Here is my code:

import sys
import cfscrape
from bs4 import BeautifulSoup
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication

class Scraper():
    def getNameOfTheDay():
        spider = cfscrape.CloudflareScraper()

        with spider:
            nameData = spider.get("https://www.babynames.com/").content

            soup = BeautifulSoup(nameData, "lxml")
            nameContainer = soup.find("div", {"class": "notd-name"})
            name = nameContainer.text
            return name

class NameScraper(QMainWindow):
    def __init__(self):
        super(NameScraper, self).__init__()
        self.setWindowTitle("Name Scraper")
        self.setFixedSize(644, 591)

        self.nameScraperUI()

        font = QtGui.QFont()
        font.setFamily("Segoe UI")
        font.setPointSize(10)

    def nameScraperUI(self):
        self.nameOfTheDayLbl = QtWidgets.QLabel(self)
        self.nameOfTheDayLbl.setGeometry(50, 50, 300, 15)
        self.nameOfTheDayLbl.setText("Name of The Day")

        self.scrapeBtn = QtWidgets.QPushButton(self)
        self.scrapeBtn.setGeometry(QtCore.QRect(230, 500, 181, 41))
        self.scrapeBtn.setText("Scrape Names")
        self.scrapeBtn.setObjectName("pushButton")
        self.scrapeBtn.clicked.connect(partial(self.updateLbl, self.nameOfTheDayLbl, Scraper.getNameOfTheDay))

    def updateLbl(self, label, text):
        label.setText(str(text))

def window():
    app = QtWidgets.QApplication(sys.argv)
    mainWin = NameScraper()
    mainWin.show()
    sys.exit(app.exec_())

window()

I don't see the need to use partial since you can do the following:

    self.scrapeBtn.setObjectName("pushButton")
    self.scrapeBtn.clicked.connect(self.updateLbl)

def updateLbl(self):
    self.nameOfTheDayLbl.setText(Scraper.getNameOfTheDay())

But if you still want to use partial then you should evaluate the function:

self.scrapeBtn.clicked.connect(partial(self.updateLbl, self.nameOfTheDayLbl, Scraper.getNameOfTheDay()))

But even so it would generate an error since it needs a parameter so you must use the @staticmethod decorator:

class Scraper():
    @staticmethod
    def getNameOfTheDay():
        # ...

With the previous change, a problem still arises: The GUI freezes because the scraper task is very time consuming, so to avoid that problem it must be implemented in another thread. Considering all of the above, the solution is:

import sys
import threading

import cfscrape

from bs4 import BeautifulSoup

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication


class Scraper:
    @staticmethod
    def getNameOfTheDay():
        spider = cfscrape.CloudflareScraper()

        with spider:
            nameData = spider.get("https://www.babynames.com/").content

            soup = BeautifulSoup(nameData, "lxml")
            nameContainer = soup.find("div", {"class": "notd-name"})
            name = nameContainer.text
            return name


class QScraper(QtCore.QObject):
    nameSignal = QtCore.pyqtSignal(str)

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

    def _execute(self):
        self.nameSignal.emit(Scraper.getNameOfTheDay())


class NameScraper(QMainWindow):
    def __init__(self):
        super(NameScraper, self).__init__()
        self.setWindowTitle("Name Scraper")
        self.setFixedSize(644, 591)

        self.q_scraper = QScraper()

        self.nameScraperUI()

        self.q_scraper.nameSignal.connect(self.nameOfTheDayLbl.setText)

    def nameScraperUI(self):
        self.nameOfTheDayLbl = QtWidgets.QLabel(self)
        self.nameOfTheDayLbl.setGeometry(50, 50, 300, 15)
        self.nameOfTheDayLbl.setText("Name of The Day")

        self.scrapeBtn = QtWidgets.QPushButton(self)
        self.scrapeBtn.setGeometry(QtCore.QRect(230, 500, 181, 41))
        self.scrapeBtn.setText("Scrape Names")
        self.scrapeBtn.setObjectName("pushButton")
        self.scrapeBtn.clicked.connect(self.q_scraper.start)


def window():
    app = QtWidgets.QApplication(sys.argv)
    mainWin = NameScraper()
    mainWin.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    window()

Note: The @dahanraz solution is incorrect since getNameOfTheDay() is running when creating the GUI and not when pressing the button.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM