Есть ли способ получить класс страницы в Pyqt5 в браузере? - PullRequest
0 голосов
/ 04 марта 2020

Я работаю с pyqt5. Я хочу, чтобы пользователь щелкнул браузер, который должен быть встроен в мое приложение pyqt5, чтобы получить класс элемента, на который он / она щелкает по нему.

Я только что обнаружил при переполнении стека, что это выполнимо путем объединения javascript код с python. Есть идеи, как извлечь класс элемента?

1 Ответ

1 голос
/ 04 марта 2020

Решение состоит в том, чтобы добавить «прослушиватель событий», который делает возможной связь между объектами DOM и (Py) Qt.

Следующее решение основано на этом ответе .

from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel
from jinja2 import Template

class Element(QtCore.QObject):
    def __init__(self, name, parent=None):
        super(Element, self).__init__(parent)
        self._name = name

    @property
    def name(self):
        return self._name

    def script(self):
        return ""

class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self, parent=None):
        super(WebEnginePage, self).__init__(parent)
        self.loadFinished.connect(self.onLoadFinished)
        self._objects = []
        self._scripts = []

    def add_object(self, obj):
        self._objects.append(obj)

    @QtCore.pyqtSlot(bool)
    def onLoadFinished(self, ok):
        print("Finished loading: ", ok)
        if ok:
            self.load_qwebchannel()
            self.add_objects()

    def load_qwebchannel(self):
        file = QtCore.QFile(":/qtwebchannel/qwebchannel.js")
        if file.open(QtCore.QIODevice.ReadOnly):
            content = file.readAll()
            file.close()
            self.runJavaScript(content.data().decode())
        if self.webChannel() is None:
            channel = QtWebChannel.QWebChannel(self)
            self.setWebChannel(channel)

    def add_objects(self):
        if self.webChannel() is not None:
            objects = {obj.name: obj for obj in self._objects}
            self.webChannel().registerObjects(objects)
            _script = """
            {% for obj in objects %}
            var {{obj}};
            {% endfor %}
            new QWebChannel(qt.webChannelTransport, function (channel) {
            {% for obj in objects %}
                {{obj}} = channel.objects.{{obj}};
            {% endfor %}
            }); 
            """
            self.runJavaScript(Template(_script).render(objects=objects.keys()))
            for obj in self._objects:
                if isinstance(obj, Element):
                    self.runJavaScript(obj.script())


class Helper(Element):
    classClicked = QtCore.pyqtSignal(str)

    def script(self):
        js = """
        document.addEventListener('click', function(e) {
            e = e || window.event;
            var target = e.target || e.srcElement;
            {{name}}.objectClicked(target.className);
        }, false);"""
        return Template(js).render(name=self.name)

    @QtCore.pyqtSlot(str)
    def objectClicked(self, className):
        if className:
            self.classClicked.emit(className)

if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    classname_helper = Helper("classname_helper")
    classname_helper.classClicked.connect(lambda name: print("clicked", name))
    view = QtWebEngineWidgets.QWebEngineView()
    page = WebEnginePage()
    page.add_object(classname_helper)
    view.setPage(page)
    view.load(QtCore.QUrl("https://stackoverflow.com/questions/60524774"))
    view.show()
    sys.exit(app.exec_())
...