如何将内容写入QNetworkReply(是:带有生成内容的QWebview)

时间:2017-12-31 16:57:33

标签: python qt qwebview

我正在使用QWebview来显示由同一程序生成的html。现在,html可以引用其他资源,例如fram集中的<FRAME src=...>。当浏览器开始下载该资源时,我必须自己拦截该请求并提供内容,因为没有涉及的网络服务器。我可以使用哪些钩子来查找请求的URL并提供生成的内容?

创建浏览器小部件:

self.browser = QWebView()
self.layout.addWidget(self.browser)

加载框架集:

self.browser.setHtml(ret.text)

现在我期望找到的是一些信号然后

self.browser.requestURI.connect(myhandler)

但我没有看到类似的东西。这里有什么更好的方法?

编辑:

主要问题似乎是使用 setHtml 。因此,似乎绕过了所有加载机制。将 load() QNetworkAccessManager 结合使用,效果更佳(见下文)。现在响应对象被提供给我的内容管理器,但是,我无法向响应对象写入任何内容(或实例化一个新的)。可以通过访问模式参数打开它。然后READ-ONLY错误消失,但仍然返回-1。

我相应地重述了这个问题的标题。

from PyQt5.Qt import *  # @UnusedWildImport

class ContentManager(object):
    def handleRequest(self, request, response):
#         response.writeData(bytearray("hello new year", "utf-8")) #THIS WORKS NOT
        return response


class NAM(QNetworkAccessManager):
    def __init__(self, contentManager):
        super().__init__()
        self.contentManager = contentManager

    def createRequest(self, operation, request, device):
        response = super().createRequest(operation, request, device)
        return self.contentManager.handleRequest(request, response)

class Browser(QWidget):
    def __init__(self):
        super().__init__()

    def open(self, url):
        self.browser.load(QUrl(url))

    def build(self, contentManager):
        layout = QVBoxLayout(self)

        view = QWebView()
        page = view.page(); view.setPage(page)
        page.setNetworkAccessManager(NAM(contentManager))
        layout.addWidget(view)

        self.browser = view        

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w   = Browser()
    w.build(ContentManager())
    w.open("index.html")
    w.show()

    app.exec_() 

1 个答案:

答案 0 :(得分:3)

您需要实施自定义QNetworkReply,一般情况下,您可以随心所欲地投放任何内容{&#39;到webview(html,text,images)。

我不确定本地文件和框架,但是当您使用虚假域名时#39;必须由QNetworkAccessManager解决它才能解决。

以下非常简单的示例使用Python 3.6.3和PyQt 5.10.0:

from PyQt5.Qt import *  # @UnusedWildImport
import signal, os, sys
signal.signal(signal.SIGINT, signal.SIG_DFL)


class ContentHandler(object):
    def __init__(self, url):
        self.url = url

    def __call__(self):
        print ('ContentHandler >>', self.url)
        path, basename = os.path.split(self.url)

        if basename == 'index.html':
            return b"hello new year", 'text/html'


class DownloadReply(QNetworkReply):
    def __init__(self, parent, operation, request):
        super(DownloadReply, self).__init__(parent)
        self.setRequest(request)
        self.setOperation(operation)
        self.setUrl(request.url())
        self.bytes_read = 0
        self.content = b''

        # give webkit time to connect to the finished and readyRead signals
        QTimer.singleShot(200, self.load_content)

    def load_content(self):
        self.content, self.data = ContentHandler(str(self.url().toString()))()
        self.offset = 0

        self.open(QIODevice.ReadOnly | QIODevice.Unbuffered)
        self.setHeader(QNetworkRequest.ContentTypeHeader, QVariant(self.data))
        self.setHeader(QNetworkRequest.ContentLengthHeader, QVariant(len(self.content)))

        self.readyRead.emit()
        self.finished.emit()

    def abort(self):
        pass

    def isSequential(self):
        return True

    def bytesAvailable(self):
        ba = len(self.content) - self.bytes_read + super(DownloadReply, self).bytesAvailable()
        return ba

    def readData(self, size):
        if self.bytes_read >= len(self.content):
            return None
        data = self.content[self.bytes_read:self.bytes_read + size]
        self.bytes_read += len(data)
        return data

    def manager(self):
        return self.parent()


class NetworkAccessManager(QNetworkAccessManager):
    def __init__(self, parent=None):
        super(NetworkAccessManager, self).__init__(parent=parent)

    def createRequest(self, operation, request, device):
        if str(request.url().host()).lower() == "myfakedom.ain":
            print ('request:', request.url().host())
            return DownloadReply(self, self.GetOperation, request)
        return super(NetworkAccessManager, self).createRequest(operation, request, device)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    webView = QWebView()
    webView.settings().setAttribute(QWebSettings.PluginsEnabled, True)
    webView.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
    webView.settings().setAttribute(QWebSettings.AutoLoadImages, True)
    webView.settings().setAttribute(QWebSettings.JavascriptEnabled, True)

    webInspector = QWebInspector()

    nam = NetworkAccessManager()
    webView.page().setNetworkAccessManager(nam)
    webView.load(QUrl('http://myFakeDom.ain/index.html'))
    webInspector.setPage(webView.page())

    window = QMainWindow()
    window.setCentralWidget(webView)
    window.setFixedSize(1200, 840)
    window.setWindowTitle('Test')
    window.show()

    sys.exit(app.exec_())