Обслуживание ресурса для QWebView PyQT5
Как обслуживать ресурс (файлы, такие как html, css, js, шрифты) для приложения для настольного компьютера в QWebView (в PyQT5)?
Что я хочу это:
- Если возможно, обработка запрошенного ресурса с помощью движка Webkit PyQT5 по специальной схеме, например, скажем
custom://app/jquery.js
и возвращая файл. - Если возможно, обработка стандартных HTTP-глаголов (GET, POST, ...) для этой пользовательской схемы.
Если эти 2 невозможны (по крайней мере, невозможны чисто Pythonic способом):
- Как я могу перехватывать запросы, поступающие от встроенного Webkit, и предоставлять ресурс (html, css, js) на основе шаблона в URL (как, скажем, некоторые регулярные выражения)
(?<controller>[^/])/(?<action>[^/])
)?
1 ответ
Решение
Вам нужно создать свой собственный подкласс QNetworkAccessManager, который возвращает пользовательский QNetworkReply для желаемого протокола, а затем установить его в качестве диспетчера сетевого доступа для вашей страницы QWebView.
В этой статье показан хороший пример того, как это можно сделать - применительно к PyQt5 это выглядит так:
from PyQt5.QtCore import QUrl, QTimer, QIODevice
from PyQt5.QtWidgets import QApplication
from PyQt5.QtNetwork import (QNetworkAccessManager,
QNetworkReply,
QNetworkRequest)
from PyQt5.QtWebKitWidgets import QWebView
import sys
class ExampleNetworkAccessManager(QNetworkAccessManager):
def __init__(self, parent=None):
super().__init__(parent=parent)
def createRequest(self, operation, request, device):
if request.url().scheme() == 'example':
return ExampleReply(self, operation, request, device)
return super().createRequest(operation, request, device)
class ExampleReply(QNetworkReply):
def __init__(self, parent, operation, request, device):
super().__init__(parent=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):
if self.operation() == QNetworkAccessManager.PostOperation:
# handle operations ...
pass
# some dummy content for this example
self.content = b'''<html>
<h1>hello world!</h1>
<p>...</p>
</html>'''
self.open(QIODevice.ReadOnly | QIODevice.Unbuffered)
self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.content))
self.setHeader(QNetworkRequest.ContentTypeHeader, "text/html")
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().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()
if __name__ == '__main__':
app = QApplication(sys.argv)
wv = QWebView()
enam = ExampleNetworkAccessManager()
wv.page().setNetworkAccessManager(enam)
wv.show()
wv.setUrl(QUrl("example://test.html"))
app.exec()