Извлечение определенных частей веб-страницы с помощью PyQt5 и их отображение - PullRequest
1 голос
/ 05 мая 2020

Я хочу создать приложение GUI, которое запрашивает у пользователя чемпиона, которого они хотят проверить, а затем его роль (например, средний, джунгли, верхний, AD C, поддержка), а затем будет отображать «Наиболее частые Руны »и некоторые другие данные на сайте. Я считаю, что PyQt5 будет лучшим python GUI для этого, поскольку он имеет встроенные веб-страницы, но, пожалуйста, предложите альтернативы.

С этим кодом:

from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWidgets import QApplication
import sys

#champion = input("What champion would you like to check? ")
champions = "Katarina"
#role = input("What role are you playing (Middle, Jungle, Top, ADC, Support)? ")
roles = "Middle"
URL = f"https://champion.gg/champion/{champions.capitalize()}/{roles.capitalize()}?"

app = QApplication(sys.argv)

web = QWebEngineView()
web.load(QUrl(URL))
web.show()

sys.exit(app.exec_())

Он отображает всю веб-страницу, но мне нужен только раздел «Наиболее часто встречающиеся руны», как это:

enter image description here

, а затем сохраните его как переменную (QLabel?), Которую затем можно разместить где угодно. Я пытался понять, как это сделать, но не смог найти решения. Я бы предпочел сделать это с помощью tkinter, но кажется, что это невозможно (или, насколько мне удалось понять - если это способ, пожалуйста, объясните как можно больше, как).

I попытался очистить веб-сайт с помощью bs4 и запросов с этим кодом:

from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import *
from bs4 import BeautifulSoup
import requests
import time
import sys

#champion = input("What champion would you like to check? ")
champions = "Katarina"
#role = input("What role are you playing (Middle, Jungle, Top, ADC, Support)? ")
roles = "Middle"
URL = f"https://champion.gg/champion/{champions.capitalize()}/{roles.capitalize()}?"

app = QApplication(sys.argv)

page = requests.get('https://champion.gg/champion/Katarina/Middle?')

soup = BeautifulSoup(page.text, 'lxml')

championData = soup.find('div', 'summoner-text')


window = QWidget()


window.setWindowTitle("League of Legends helper")
window.setGeometry(100, 100, 550, 250)


runes = QLabel(championData, parent=window)

, но он просто выдает ошибки, которые я не смог полностью понять.

Ошибка:

Traceback (most recent call last):
  File "(FILEPATH)", line 32, in <module>
    runes = QLabel(championData, parent=window)
TypeError: arguments did not match any overloaded call:
  QLabel(parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()): argument 1 has unexpected type 'Tag'
  QLabel(str, parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()): argument 1 has unexpected type 'Tag'

1 Ответ

1 голос
/ 06 мая 2020

BeautifulSoup - это синтаксический анализатор HTML, поэтому каждый узел DOM имеет оболочку, которая позволяет получить доступ к его свойствам, поэтому championData не является строкой, вызывающей ошибку.

Даже в этом случае вы должны извлечь HTML с узла, это было бы бесполезно, потому что библиотека «запросов» не получает HTML, динамически сгенерированного javascript, кроме того, стили не будут сохранены, поскольку они зависят от других файлов.

Возможное решение для этого случая - извлечь HTML из этого узла и поместить его в тот же документ, используя javascript:

import sys

from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets


def main(*, champions, roles):
    url = f"https://champion.gg/champion/{champions.capitalize()}/{roles.capitalize()}?"

    app = QtWidgets.QApplication(sys.argv)

    web = QtWebEngineWidgets.QWebEngineView()
    web.resize(640, 480)

    progress_dialog = QtWidgets.QProgressDialog()
    progress_dialog.setLabelText(
        """""<p><span style=" font-size:20pt; font-weight:600;">Loadding ...</span></p>"""
    )
    progress_dialog.resize(640, 480)
    progress_dialog.show()

    web.loadProgress.connect(progress_dialog.setValue)

    button = progress_dialog.findChild(QtWidgets.QPushButton)
    if button is not None:
        button.clicked.connect(QtCore.QCoreApplication.quit)

    def on_load_finished():
        codes = [
            """var iterator = document.evaluate("/html[1]/body[1]/div[1]/div[2]/div[3]/div[2]/div[2]/div[1]/div[1]/div[2]/div[1]/div[3]", document, null, XPathResult.ANY_TYPE, null)""",
            """var e = iterator.iterateNext() """,
            """document.body.innerHTML = e.innerHTML""",
            """document.body.children[0].style.marginTop = "10px" """,
        ]
        for code in codes:
            web.page().runJavaScript(code)
        web.move(progress_dialog.pos())
        web.show()
        progress_dialog.close()

    web.loadFinished.connect(on_load_finished)
    web.load(QtCore.QUrl(url))

    sys.exit(app.exec_())


if __name__ == "__main__":
    main(champions="Katarina", roles="Middle")

enter image description here

Обновление:

import sys

from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._champion_le = QtWidgets.QLineEdit(placeholderText=self.tr("champion"))
        self._role_cb = QtWidgets.QComboBox()
        self._web = QtWebEngineWidgets.QWebEngineView()
        self._search_btn = QtWidgets.QPushButton(self.tr("Search"))
        self._stacked = QtWidgets.QStackedWidget()
        self._progress_bar = QtWidgets.QProgressBar()

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QGridLayout(central_widget)
        lay.addWidget(self._champion_le, 0, 0)
        lay.addWidget(self._role_cb, 0, 1)
        lay.addWidget(self._search_btn, 0, 2)
        lay.addWidget(self._stacked, 1, 0, 1, 3)

        container = QtWidgets.QWidget()
        lay = QtWidgets.QVBoxLayout(container)
        lay.addWidget(
            QtWidgets.QLabel(
                self.tr(
                    """<p><span style="font-size:20pt; font-weight:600;">Loadding ...</span></p>"""
                )
            )
        )
        lay.addWidget(self._progress_bar)

        self._stacked.addWidget(QtWidgets.QWidget())
        self._stacked.addWidget(container)
        self._stacked.addWidget(self._web)

        self._role_cb.addItems(["Top", "Jungle", "Middle", "ADC", "Support"])
        self._search_btn.clicked.connect(self.on_clicked)
        self._web.loadFinished.connect(self.on_load_finished)
        self._web.loadProgress.connect(self._progress_bar.setValue)

        self.resize(640, 480)

        self._champion_le.setText("Aatrox")
        self._role_cb.setCurrentText("Top")

    @QtCore.pyqtSlot()
    def on_clicked(self):
        champion = self._champion_le.text()
        role = self._role_cb.currentText()
        if champion:
            self._stacked.setCurrentIndex(1)
            self.change(champion, role)

    def change(self, champion, role):
        url = f"https://champion.gg/champion/{champion.capitalize()}/{role}?"
        self._web.load(QtCore.QUrl(url))

    @QtCore.pyqtSlot(bool)
    def on_load_finished(self, ok):
        if ok:
            codes = [
                """var iterator = document.evaluate("/html[1]/body[1]/div[1]/div[2]/div[3]/div[2]/div[2]/div[1]/div[1]/div[2]/div[1]/div[3]", document, null, XPathResult.ANY_TYPE, null)""",
                """var e = iterator.iterateNext() """,
                """document.body.innerHTML = e.innerHTML""",
                """document.body.children[0].style.marginTop = "10px" """,
            ]
            for code in codes:
                self._web.page().runJavaScript(code)
            self._stacked.setCurrentIndex(2)


def main():
    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...