Есть ли способ синхронно вызвать метод toHtml, который является объектом QWebEnginePage?

Я пытаюсь получить HTML-код из объекта QWebEnginePage. Согласно ссылке на Qt, toHtml объекта QWebEnginePage является асинхронным методом, как показано ниже.

Асинхронный метод для извлечения содержимого страницы в виде HTML, заключенного в теги HTML и BODY. После успешного завершения resultCallback вызывается с содержимым страницы.

поэтому я попытался выяснить, как вызвать этот метод синхронно.

результат, который я хочу получить, ниже.

class MainWindow(QWidget):
  html = None
  ...
  ...
  def store_html(self, data):
    self.html = data

  def get_html(self):
    current_page = self.web_view.page()
    current_page.toHtml(self.store_html)
    # I want to wait until the 'store_html' method is finished
    # but the 'toHtml' is called asynchronously, return None when try to return self.html value like below.
    return self.html 
  ...
  ...

Спасибо, что прочитали это.

Всем хорошего дня.

3 ответа

Решение

Простой способ получить такое поведение - использовать QEventLoop(), Объект этого класса предотвращает код, который после exec_() от того, чтобы быть выполненным, это не означает, что GUI не продолжает работать.

class Widget(QWidget):
    toHtmlFinished = pyqtSignal()

    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        self.setLayout(QVBoxLayout())
        self.web_view = QWebEngineView(self)
        self.web_view.load(QUrl("http://doc.qt.io/qt-5/qeventloop.html"))
        btn = QPushButton("Get HTML", self)
        self.layout().addWidget(self.web_view)
        self.layout().addWidget(btn)
        btn.clicked.connect(self.get_html)
        self.html = ""

    def store_html(self, html):
        self.html = html
        self.toHtmlFinished.emit()

    def get_html(self):
        current_page = self.web_view.page()
        current_page.toHtml(self.store_html)
        loop = QEventLoop()
        self.toHtmlFinished.connect(loop.quit)
        loop.exec_()
        print(self.html)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

Здесь другой подход, а также другое поведение по сравнению с QEventLoopметод

Вы можете создать подкласс из QWebEngineViewи расширить load()функциональность с loadFinishedПодайте сигнал и создайте собственный метод read_html()

      class MyWebView(QWebEngineView):

    def __init__(self, parent):
        super(MyWebView, self).__init__(parent)
        self.html = None

    def read_html(self, url):
        """
        Load url and read webpage content in html
        """
        def read_page():
            def process_html(html):
                self.html = html
            self.page().toHtml(process_html)

        self.load(url)
        self.loadFinished.connect(read_page)

таким образом, приложение не будет останавливаться, ожидая завершения загрузки страницы в цикле событий, но как только страница будет загружена, вы сможете получить доступ к содержимому HTML.

      class MainWindow(QWidget):
    def __int__(self):
        ...
        self.web_view = MyWebView(self)
        self.web_view.read_html(r'https://www.xingyulei.com/')
        ...
        self.btn.clicked.connect(self.print_html)

    def print_html(self):
        print(self.view.html)

Вы можете использовать объект multiprocessing.Connection, созданный в качестве одной стороны метода send multiprocessing.Pipe, в качестве обратного вызова, а затем сразу же использовать другой конец метода recv канала. Recv будет блокироваться до получения html, так что имейте это в виду

пример:

from multiprocessing import Pipe

class MainWindow(QWidget):
    def __init__(...):
        ...
        self.from_loopback,self.to_loopback=Pipe(False)

    def get_html(self):
        current_page = self.web_view.page()
        current_page.toHtml(self.to_loopback.send)
        return self.from_loopback.recv() 
Другие вопросы по тегам