I'm currently working with PyQt5 and PyQtWebEngine and I want to create a small browser.
OS and version info:
- Windows 10
- Python 3.9.6
- PyQt5 5.15.6
- PyQtWebEngine 5.15.5
I installed all these packages using pip for PyQt5 and PyQtWebEngine.
The problem I have is that when I go on Twitter for example, videos are not loaded (images are) and there is a error message on the video.
Also, I can scroll only few posts until python crashes without any error printed anywhere (not only the browser part, but python entirely: it's not the browser closing himself, that's why I can't find a solution to this).
The code of the browser is shown below:
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWebEngineWidgets
class BrowserWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(BrowserWindow, self).__init__(*args, **kwargs)
# ADD WINDOW ELEMENTS
# ADD TAB WIGDETS TO DISPLAY WEB TABS
self.tabs = QTabWidget()
self.tabs.setDocumentMode(True)
self.tabs.setTabsClosable(True)
self.setCentralWidget(self.tabs)
# ADD DOUBLE CLICK EVENT LISTENER
self.tabs.tabBarDoubleClicked.connect(self.tab_open_doubleclick)
# ADD TAB CLOSE EVENT LISTENER
self.tabs.tabCloseRequested.connect(self.close_current_tab)
# ADD ACTIVE TAB CHANGE EVENT LISTENER
self.tabs.currentChanged.connect(self.current_tab_changed)
# ADD NAVIGATION TOOLBAR
navtb = QToolBar("Navigation")
navtb.setIconSize(QtCore.QSize(16, 16))
self.addToolBar(navtb)
# ADD BUTTONS TO NAVIGATION TOOLBAR
# PREVIOUS WEB PAGE BUTTON
back_btn = QAction(QtGui.QIcon('arrow back.png'), "Back", self)
back_btn.setStatusTip("Back to previous page")
navtb.addAction(back_btn)
# NAVIGATE TO PREVIOUS PAGE
back_btn.triggered.connect(lambda: self.tabs.currentWidget().back())
# NEXT WEB PAGE BUTTON
next_btn = QAction(QtGui.QIcon('arrow next.png'), "Forward", self)
next_btn.setStatusTip("Forward to next page")
navtb.addAction(next_btn)
# NAVIGATE TO NEXT WEB PAGE
next_btn.triggered.connect(lambda: self.tabs.currentWidget().forward())
# REFRESH WEB PAGE BUTTON
reload_btn = QAction(QtGui.QIcon('refresh.png'), "Reload", self)
reload_btn.setStatusTip("Reload page")
navtb.addAction(reload_btn)
# RELOAD WEB PAGE
reload_btn.triggered.connect(lambda: self.tabs.currentWidget().reload())
# HOME PAGE BUTTON
home_btn = QAction(QtGui.QIcon('home.png'), "Home", self)
home_btn.setStatusTip("Go home")
navtb.addAction(home_btn)
# NAVIGATE TO DEFAULT HOME PAGE
home_btn.triggered.connect(self.navigate_home)
# ADD SEPARATOR TO NAVIGATION BUTTONS
navtb.addSeparator()
# ADD LINE EDIT TO SHOW AND EDIT URLS
self.urlbar = QLineEdit()
navtb.addWidget(self.urlbar)
# LOAD URL WHEN ENTER BUTTON IS PRESSED
self.urlbar.returnPressed.connect(self.navigate_to_url)
self.urlbar.mousePressEvent = lambda _ : self.urlbar.selectAll()
# ADD STYLESHEET TO CUSTOMIZE YOUR WINDOWS
self.setStyleSheet("""QWidget{
background-color: white;
color: rgb(48, 48, 48);
}
QTabWidget::pane { /* The tab widget frame */
border-top: 2px solid rgb(255, 255, 255);
position: absolute;
color: rgb(90, 90, 90);
padding: 5px;
}
QTabWidget::tab-bar {
alignment: left;
}
/* Style the tab using the tab sub-control. Note that
it reads QTabBar _not_ QTabWidget */
QLabel, QToolButton {
background: rgb(255, 255, 255);
border: 2px solid rgb(255, 255, 255);
/*border-bottom-color: #C2C7CB; /* same as the pane color */
border-radius: 3px;
min-width: 8ex;
padding: 5px;
margin-right: 2px;
color: rgb(50, 50, 50);
}
QLabel:hover, QToolButton::hover {
background: white;
border: 2px solid rgb(0, 36, 36);
background-color: white;
}
QTabBar::tab{
border-radius: 3px;
min-width: 8ex;
padding: 5px;
margin-right: 2px;
color: rgb(50, 50, 50);
background:#e0e0e0;
}
QTabBar::tab:selected, QTabBar::tab:hover:selected{
background:white;
background-color:white;
border-bottom-width:0px;
border-bottom-left-radius:0px;
border-bottom-right-radius:0px;
}
QTabBar::tab:hover {
background:#ededed;
background-color:#ededed;
border-color:#ededed;
}
QLineEdit {
border: 2px solid rgb(0, 36, 36);
border-radius: 3px;
padding: 5px;
background-color: white;
color: rgb(50, 50, 50);
}
QLineEdit:hover {
border: 2px solid rgb(0, 66, 124);
}
QLineEdit:focus{
border: 2px solid rgb(0, 136, 255);
}
QPushButton{
background: rgb(49, 49, 49);
border: 2px solid rgb(0, 36, 36);
background-color: rgb(0, 36, 36);
padding: 5px;
border-radius: 10px;
}""")
#label = Homepage
self.add_new_tab(QtCore.QUrl('https://duckduckgo.com/'), 'Homepage')
# SHOW MAIN WINDOW
self.show()
# ############################################
# FUNCTIONS
##############################################
# ADD NEW WEB TAB
def add_new_tab(self, qurl=None, label="Blank"):
# Check if url value is blank
if qurl is None:
qurl = QtCore.QUrl('')#pass empty string to url
# Load the passed url
browser = QtWebEngineWidgets.QWebEngineView()
browser.setUrl(qurl)
# ADD THE WEB PAGE TAB
i = self.tabs.addTab(browser, label)
self.tabs.setCurrentIndex(i)
# ADD BROWSER EVENT LISTENERS
# On URL change
browser.urlChanged.connect(lambda qurl, browser=browser:
self.update_urlbar(qurl, browser))
# On loadfinished
browser.loadFinished.connect(lambda _, i=i, browser=browser:
self.tabs.setTabText(i, browser.page().title()))
# ADD NEW TAB ON DOUBLE CLICK ON TABS
def tab_open_doubleclick(self, i):
if i == -1: # No tab under the click
self.add_new_tab()
# CLOSE TABS
def close_current_tab(self, i):
if self.tabs.count() < 2: #Only close if there is more than one tab open
return
self.tabs.removeTab(i)
# UPDATE URL TEXT WHEN ACTIVE TAB IS CHANGED
def update_urlbar(self, q, browser=None):
#q = QURL
if browser != self.tabs.currentWidget():
# If this signal is not from the current tab, ignore
return
self.urlbar.setText(q.toString())
self.urlbar.setCursorPosition(0)
# ACTIVE TAB CHANGE ACTIONS
def current_tab_changed(self, i):
# i = tab index
# GET CURRENT TAB URL
qurl = self.tabs.currentWidget().url()
# UPDATE URL TEXT
self.update_urlbar(qurl, self.tabs.currentWidget())
# UPDATE WINDOWS TITTLE
self.update_title(self.tabs.currentWidget())
# UPDATE WINDOWS TITTLE
def update_title(self, browser):
if browser != self.tabs.currentWidget():
# If this signal is not from the current ACTIVE tab, ignore
return
title = self.tabs.currentWidget().page().title()
self.setWindowTitle(title)
# NAVIGATE TO PASSED URL
def navigate_to_url(self): # Does not receive the Url
# GET URL TEXT
q = QtCore.QUrl(self.urlbar.text())
if q.scheme() == "":
q = QtCore.QUrl('https://www.google.com/search?q='+self.urlbar.text().replace(' ', '+'))
self.tabs.currentWidget().setUrl(q)
# NAVIGATE TO DEFAULT HOME PAGE
def navigate_home(self):
self.tabs.currentWidget().setUrl(QtCore.QUrl("https://duckduckgo.com/"))
app = QApplication(sys.argv)
w = BrowserWindow()
app.exec_()
EDIT : I was running it in the VSC terminal, just tried on a cmd one and I got errors :
[1436:6100:0617/142809.070:ERROR:cache_util_win.cc(21)] Unable to move the cache: AccÞs refusÚ. (0x5)
[1436:6100:0617/142809.084:ERROR:cache_util.cc(139)] Unable to move cache folder C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\GPUCache to C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\old_GPUCache_000
[1436:6100:0617/142809.096:ERROR:disk_cache.cc(184)] Unable to create cache
[1436:6100:0617/142809.096:ERROR:shader_disk_cache.cc(606)] Shader Cache Creation failed: -2
[1436:6100:0617/142812.075:ERROR:service_worker_storage.cc(1575)] Failed to delete the database: Database IO error
[1436:1208:0617/142837.652:ERROR:leveldb_factory.cc(91)] Failed to open LevelDB database from C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb,IO error: C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb/LOCK: File currently in use. (ChromeMethodBFE: 15::LockFile::2)
[1436:1208:0617/142839.674:ERROR:leveldb_factory.cc(91)] Failed to open LevelDB database from C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb,IO error: C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb/LOCK: File currently in use. (ChromeMethodBFE: 15::LockFile::2)
Example of a media that can't be loaded:
EDIT 2 :
So after some work on it, it seems that there is a problem with local storage/forage (I don't have any knowledge about that) :
I'm running another QWebEngineView for other purposes, he shows widget that I get from TradingView so I don't write the html for it. Actually this part throws js warnings or erros that you can see below.
They could be linked to the ones described before.
js: 2022-06-29T15:25:55.559Z:Common.LocalForage:IndexedDB is NOT available
js: 2022-06-29T15:25:55.816Z:ChartApi.Core:Cannot get studies_metadata, reason: Error: No available storage method found.
js: 2022-06-29T15:25:56.679Z:ChartApi.Core:Cannot update studies_metadata cache, reason: Error: No available storage method found.
