如何将内容写入 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_())
我正在使用 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_())