2016-06-10 49 views
6

Làm cách nào để "kết xuất" HTML với PyQt5 v5.6 QWebEngineView?Cách "hiển thị" HTML với QWebEngineView của PyQt5

Trước đây tôi đã thực hiện tác vụ với PyQt5 v5.4.1 QWebPage, nhưng nó là suggested để thử QWebEngineView mới hơn.

Dưới đây là thực hiện điều đó (nó thường làm việc như mong đợi, nhưng có xu hướng treo vô thời hạn đối với một số trang web và các tình huống):

def render(source_html): 
    """Fully render HTML, JavaScript and all.""" 

    import sys 
    from PyQt5.QtWidgets import QApplication 
    from PyQt5.QtWebKitWidgets import QWebPage 

    class Render(QWebPage): 
     def __init__(self, html): 
      self.html = None 
      self.app = QApplication(sys.argv) 
      QWebPage.__init__(self) 
      self.loadFinished.connect(self._loadFinished) 
      self.mainFrame().setHtml(html) 
      self.app.exec_() 

     def _loadFinished(self, result): 
      self.html = self.mainFrame().toHtml() 
      self.app.quit() 

    return Render(source_html).html 

import requests 
sample_html = requests.get(dummy_url).text 
print(render(sample_html)) 

gì sau nỗ lực của tôi lúc sử dụng QWebEngineView là. Thứ nhất, quá trình cài đặt và thiết lập của PyQt5 v5.6 trên Ubuntu:

# install PyQt5 v5.6 wheel from PyPI 
pip3 install --user pyqt5 

# link missing resources 
ln -s ../resources/icudtl.dat ../resources/qtwebengine_resources.pak ../resources/qtwebengine_resources_100p.pak ../resources/qtwebengine_resources_200p.pak ../translations/qtwebengine_locales ~/.local/lib/python3.5/site-packages/PyQt5/Qt/libexec/ 

Bây giờ cho các Python ... Kết quả sau một lỗi segmentation:

def render(source_html): 
    """Fully render HTML, JavaScript and all.""" 

    import sys 
    from PyQt5.QtWidgets import QApplication 
    from PyQt5.QtWebEngineWidgets import QWebEngineView 

    class Render(QWebEngineView): 
     def __init__(self, html): 
      self.html = None 
      self.app = QApplication(sys.argv) 
      QWebEngineView.__init__(self) 
      self.loadFinished.connect(self._loadFinished) 
      self.setHtml(html) 
      self.app.exec_() 

     def _loadFinished(self, result): 
      # what's going on here? how can I get the HTML from toHtml? 
      self.page().toHtml(self.callable) 
      self.app.quit() 

     def callable(self, data): 
      self.html = data 

    return Render(source_html).html 

import requests 
sample_html = requests.get(dummy_url).text 
print(render(sample_html)) 

Vấn đề dường như nằm trong cuộc gọi đến không đồng bộ toHtml(). Có vẻ như nó khá đơn giản, nhưng tôi không biết phải làm gì với nó. Tôi thấy nó là discussed trong ngữ cảnh của C++, nhưng tôi không chắc chắn làm thế nào để dịch này sang Python. Làm thế nào tôi có thể lấy HTML ra?

Trả lời

7

Khá một chút của cuộc thảo luận về chủ đề này đã được thực hiện trong các chủ đề sau: https://riverbankcomputing.com/pipermail/pyqt/2015-January/035324.html

Giao diện QWebEngine mới xem xét đến thực tế là cơ bản động cơ Chromium là không đồng bộ. Như vậy chúng ta phải biến một API không đồng bộ thành một API đồng bộ.

Dưới đây là làm thế nào mà trông:

def render(source_html): 
    """Fully render HTML, JavaScript and all.""" 

    import sys 
    from PyQt5.QtCore import QEventLoop 
    from PyQt5.QtWidgets import QApplication 
    from PyQt5.QtWebEngineWidgets import QWebEngineView 

    class Render(QWebEngineView): 
     def __init__(self, html): 
      self.html = None 
      self.app = QApplication(sys.argv) 
      QWebEngineView.__init__(self) 
      self.loadFinished.connect(self._loadFinished) 
      self.setHtml(html) 
      while self.html is None: 
       self.app.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers | QEventLoop.WaitForMoreEvents) 
      self.app.quit() 

     def _callable(self, data): 
      self.html = data 

     def _loadFinished(self, result): 
      self.page().toHtml(self._callable) 

    return Render(source_html).html 

import requests 
sample_html = requests.get(dummy_url).text 
print(render(sample_html)) 
4

Như bạn chỉ ra, Qt5.4 dựa trên các cuộc gọi async. Không nhất thiết phải sử dụng Vòng lặp (như đã thấy trong câu trả lời của bạn), vì sai lầm duy nhất của bạn là gọi quit trước khi cuộc gọi toHtml kết thúc.

def render(source_html): 
    """Fully render HTML, JavaScript and all.""" 

    import sys 
    from PyQt5.QtWidgets import QApplication 
    from PyQt5.QtWebEngineWidgets import QWebEngineView 

    class Render(QWebEngineView): 
     def __init__(self, html): 
      self.html = None 
      self.app = QApplication(sys.argv) 
      QWebEngineView.__init__(self) 
      self.loadFinished.connect(self._loadFinished) 
      self.setHtml(html) 
      self.app.exec_() 

     def _loadFinished(self, result): 
      # This is an async call, you need to wait for this 
      # to be called before closing the app 
      self.page().toHtml(self.callable) 

     def callable(self, data): 
      self.html = data 
      # Data has been stored, it's safe to quit the app 
      self.app.quit() 

    return Render(source_html).html 

import requests 
sample_html = requests.get(dummy_url).text 
print(render(sample_html)) 
1

Câu trả lời bởi Sáu & Veehmot là rất tốt, nhưng tôi phát hiện ra rằng cho mục đích của tôi đó là không đủ, vì nó không mở rộng các yếu tố thả xuống của trang mà tôi muốn cạo. Sửa đổi nhỏ đã sửa lỗi này:

def render(url): 
    """Fully render HTML, JavaScript and all.""" 

    import sys 
    from PyQt5.QtCore import QEventLoop,QUrl 
    from PyQt5.QtWidgets import QApplication 
    from PyQt5.QtWebEngineWidgets import QWebEngineView 

    class Render(QWebEngineView): 
     def __init__(self, url): 
      self.html = None 
      self.app = QApplication(sys.argv) 
      QWebEngineView.__init__(self) 
      self.loadFinished.connect(self._loadFinished) 
      self.load(QUrl(url)) 
      while self.html is None: 
       self.app.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers | QEventLoop.WaitForMoreEvents) 
      self.app.quit() 

     def _callable(self, data): 
      self.html = data 

     def _loadFinished(self, result): 
      self.page().toHtml(self._callable) 

    return Render(url).html 


print(render(dummy_url)) 
Các vấn đề liên quan