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

How to write content to QNetworkReply (was: QWebview with generated content)

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

创建浏览器小部件:

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

加载框架集:

self.browser.setHtml(ret.text)

现在我希望找到一些信号,然后

self.browser.requestURI.connect(myhandler)

但我看不出有什么相似之处。这里有什么更好的方法?


编辑:

主要问题似乎是使用 setHtml。因此,所有加载机制似乎都被绕过了。将 load()QNetworkAccessManager 结合使用,我得到了更好的结果(见下文)。现在 response-object 已提供给我的内容管理器,但是,到目前为止,我未能向响应 object 写入任何内容(或实例化一个新响应)。它可以通过访问模式参数打开。然后READ-ONLY错误消失,但还是writereturns-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_() 

您需要实施自定义 QNetworkReply,一般来说,可以将您想要的任何内容 'inject' 提供给网络视图(html、文本、图像)。

我不确定本地文件和框架,但是当您使用必须由 QNetworkAccessManager 解析的 'fake domain' 时,它会起作用。

以下非常简单的示例使用 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_())