How to download csv file with QWebEngineView and QUrl - python

I'm building a program which uses QWebEngineView and QUrl to display a website in my PyQt5 app (running on Windows 10). However, I now want to be able to download a CSV file from the same website, but being a noob I can't seem to figure out how.
I'm familiar with using requests, urllib.request, urllib3, etc. for downloading files, but for this, I specifically want to do it with the QWebEngineView, as the user will have authenticated the request previously in the pyqt5 window.
The code to show the website in the first place goes like this:
self.view = QWebEngineView(self)
self.view.load(QUrl(url))
self.view.loadFinished.connect(self._on_load_finished)
self.hbox.addWidget(self.view)
Does anyone have any suggestion on how this can be achieved?

In QWebEngineView by default the downloads are not handled, to enable it you have to use the downloadRequested signal of QWebEngineProfile, this transports a QWebEngineDownloadItem that you have to accept if you want the download to start:
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.view = QtWebEngineWidgets.QWebEngineView()
self.view.page().profile().downloadRequested.connect(
self.on_downloadRequested
)
url = "https://domain/your.csv"
self.view.load(QtCore.QUrl(url))
hbox = QtWidgets.QHBoxLayout(self)
hbox.addWidget(self.view)
#QtCore.pyqtSlot("QWebEngineDownloadItem*")
def on_downloadRequested(self, download):
old_path = download.url().path() # download.path()
suffix = QtCore.QFileInfo(old_path).suffix()
path, _ = QtWidgets.QFileDialog.getSaveFileName(
self, "Save File", old_path, "*." + suffix
)
if path:
download.setPath(path)
download.accept()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
If you want to make a direct download you can use the download method of QWebEnginePage:
self.view.page().download(QtCore.QUrl("https://domain/your.csv"))
Update:
#QtCore.pyqtSlot("QWebEngineDownloadItem*")
def on_downloadRequested(self, download):
old_path = download.url().path() # download.path()
suffix = QtCore.QFileInfo(old_path).suffix()
path, _ = QtWidgets.QFileDialog.getSaveFileName(
self, "Save File", old_path, "*." + suffix
)
if path:
download.setPath(path)
download.accept()
download.finished.connect(self.foo)
def foo(self):
print("finished")

Related

I want to check whether the download is finished in pyqt5.webenginewidgets in python [duplicate]

I'm building a program which uses QWebEngineView and QUrl to display a website in my PyQt5 app (running on Windows 10). However, I now want to be able to download a CSV file from the same website, but being a noob I can't seem to figure out how.
I'm familiar with using requests, urllib.request, urllib3, etc. for downloading files, but for this, I specifically want to do it with the QWebEngineView, as the user will have authenticated the request previously in the pyqt5 window.
The code to show the website in the first place goes like this:
self.view = QWebEngineView(self)
self.view.load(QUrl(url))
self.view.loadFinished.connect(self._on_load_finished)
self.hbox.addWidget(self.view)
Does anyone have any suggestion on how this can be achieved?
In QWebEngineView by default the downloads are not handled, to enable it you have to use the downloadRequested signal of QWebEngineProfile, this transports a QWebEngineDownloadItem that you have to accept if you want the download to start:
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.view = QtWebEngineWidgets.QWebEngineView()
self.view.page().profile().downloadRequested.connect(
self.on_downloadRequested
)
url = "https://domain/your.csv"
self.view.load(QtCore.QUrl(url))
hbox = QtWidgets.QHBoxLayout(self)
hbox.addWidget(self.view)
#QtCore.pyqtSlot("QWebEngineDownloadItem*")
def on_downloadRequested(self, download):
old_path = download.url().path() # download.path()
suffix = QtCore.QFileInfo(old_path).suffix()
path, _ = QtWidgets.QFileDialog.getSaveFileName(
self, "Save File", old_path, "*." + suffix
)
if path:
download.setPath(path)
download.accept()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
If you want to make a direct download you can use the download method of QWebEnginePage:
self.view.page().download(QtCore.QUrl("https://domain/your.csv"))
Update:
#QtCore.pyqtSlot("QWebEngineDownloadItem*")
def on_downloadRequested(self, download):
old_path = download.url().path() # download.path()
suffix = QtCore.QFileInfo(old_path).suffix()
path, _ = QtWidgets.QFileDialog.getSaveFileName(
self, "Save File", old_path, "*." + suffix
)
if path:
download.setPath(path)
download.accept()
download.finished.connect(self.foo)
def foo(self):
print("finished")

PySide2 display same icon in file dialog as main window

I have a simple pyside2 application which looks kinda like this:
import sys
from PySide2.QtWidgets import QApplication, QDialog, QPushButton, QFileDialog, QVBoxLayout
from PySide2 import QtGui
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.setWindowTitle("My Form")
self.setWindowIcon(QtGui.QIcon("myicon.png"))
layout = QVBoxLayout()
self.button = QPushButton("Open dialog")
self.button.clicked.connect(self.browse)
layout.addWidget(self.button)
self.setLayout(layout)
def browse(self):
qfd = QFileDialog()
qfd.setWindowIcon(QtGui.QIcon("myicon.png"))
filename, _ = qfd.getOpenFileName(None, "Load Data", ".", "*.txt")
if __name__ == '__main__':
# Create the Qt Application
app = QApplication(sys.argv)
# Create and show the form
form = Form()
form.show()
# Run the main Qt loop
sys.exit(app.exec_())
I want to setup the same icon for the QFileDialog as the main window icon but for some reason it does not work. Is there a way to set it like I'm trying above? Thanks for ideas, pointers and help in advance! (I'm using Ubuntu 20.04)
The getOpenFileName method is a static method that creates an internal QFileDialog other than "qfd" so the icon is not applied. One possible option is not to use getOpenFileName but to create the logic only using the QFileDialog class, and another solution is to access the QFileDialog object created inside getOpenFileName using the characteristic that is a toplevel:
import sys
from PySide2 import QtCore, QtGui, QtWidgets
class Form(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.setWindowTitle("My Form")
self.setWindowIcon(QtGui.QIcon("myicon.png"))
layout = QtWidgets.QVBoxLayout(self)
self.button = QtWidgets.QPushButton("Open dialog")
self.button.clicked.connect(self.browse)
layout.addWidget(self.button)
def browse(self):
QtCore.QTimer.singleShot(0, self.handle_timeout)
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
None,
"Load Data",
".",
"*.txt",
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
def handle_timeout(self):
for w in QtWidgets.QApplication.topLevelWidgets():
if isinstance(w, QtWidgets.QFileDialog):
w.setWindowIcon(QtGui.QIcon("myicon.png"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())

Displaying Websites with Python

I am making an os in python, but I need a web browser. Currently I am using the os.startfile method to launch chrome, but I want another way. I want a program that a user can enter a webpage and displaying the web page without using chrome, firefox, safari etc.
Here is the basic framework I have:
from tkinter import *
import webbrowser as wb
window = Tk()
window.configure(bg="Dark Red")
window.geometry("1000x1000")
window.title("Hyper Web Browser")
window.iconbitmap("icon.ico")
''' Defined Functions'''
def submit_url():
wb.open_new_tab(Address_Bar.get())
file2write = open("History.txt", "a")
file2write.write(["\n", Address_Bar.get()])
return submit_url
'''Objects'''
Address_Bar = Entry(
bg="White",
bd=0,
font=("Comic", 25),
width=100
)
Tab_1 = Label(
bg="Red",
bd=0,
width=20,
height=3
)
Return = Button(
command=submit_url()
)
Address_Bar.place(x=20, y=60)
Tab_1.place(x=0, y=0)
Return.pack()
window.mainloop()
However, this program launches the web page into the user's default browser. Hence, I want to display the web page without using any other web browsers.
Here is a simpler version of webbrowser using PyQt5 :
import sys
from PyQt5 import QtWidgets,QtGui,QtCore
from PyQt5.QtWebEngineWidgets import *
app=QtWidgets.QApplication(sys.argv)
w=QWebEngineView()
w.load(QtCore.QUrl('https://google.com')) ## load google on startup
w.showMaximized()
app.exec_()
You can now add different widgets to it .
In python you have two most common ways to make a webbrowser 1. by using gtk webkit 2. by QtWebEngine under PyQt5.
Webkit is based upon Safari while QtWebEngine is based on Chromium. You can decide which one suits you the best. Hope it helps.
Something like this may be what you are looking for. This is a simple demo script that allows web browsing, without opening it in a default web browser such as chrome. (This is essentially a DIY web browser script) I hope this helps!
from functools import cached_property
import sys
import keyboard
from prompt_toolkit.key_binding import KeyBindings
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtCore import pyqtSlot
bindings = KeyBindings()
class WebView(QtWebEngineWidgets.QWebEngineView):
def createWindow(self, type_):
if not isinstance(self.window(), Browser):
return
if type_ == QtWebEngineWidgets.QWebEnginePage.WebBrowserTab:
return self.window().tab_widget.create_tab()
class TabWidget(QtWidgets.QTabWidget):
def create_tab(self):
view = WebView()
index = self.addTab(view, "...")
self.setTabIcon(index, view.icon())
view.titleChanged.connect(
lambda title, view=view: self.update_title(view, title)
)
view.iconChanged.connect(lambda icon, view=view: self.update_icon(view, icon))
self.setCurrentWidget(view)
return view
def update_title(self, view, title):
index = self.indexOf(view)
if 'DuckDuckGo' in title:
self.setTabText(index, 'Search')
else:
self.setTabText(index, title)
def update_icon(self, view, icon):
index = self.indexOf(view)
self.setTabIcon(index, icon)
class Browser(QtWidgets.QMainWindow):
def __init__(self, parent=None):
#main browser functrion
super().__init__(parent)
self.setCentralWidget(self.tab_widget)
view = self.tab_widget.create_tab()
view.load(QtCore.QUrl("https://www.duckduckgo.com/"))
QtWebEngineWidgets.QWebEngineProfile.defaultProfile().downloadRequested.connect(self.on_downloadRequested)
#QtCore.pyqtSlot("QWebEngineDownloadItem*")
def on_downloadRequested(self, download):
old_path = download.url().path()
suffix = QtCore.QFileInfo(old_path).suffix()
path, _ = QtWidgets.QFileDialog.getSaveFileName(
self, "Save File", old_path, "*." + suffix
)
if path:
download.setPath(path)
download.accept()
#cached_property
def tab_widget(self):
return TabWidget()
def main():
app = QtWidgets.QApplication(sys.argv)
w = Browser()
w.show()
w.showMaximized()
sys.exit(app.exec_())
if __name__ == "__main__":
while True:
main()

Python PyQt4 how to open image using QFileDialog

I have to write a program with an option to open an image from a file. I have to use QFileDialog and display image in QLabel, using QPixmap. I am able to use them individually but I didn't manage to combine them.
I think I need to take my image name from dlg.selectedFiles but I don't know how to choose the moment when there is useful data in it. Do I need to make a loop in my main program, and constantly check if there is image to open? Can I send a signal to my label using openAction.triggered.connect(...)?
from PyQt4 import QtGui
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
dlg = QtGui.QFileDialog(self)
openAction = QtGui.QAction('Open', self)
openAction.triggered.connect(dlg.open)
fileMenu.addAction(openAction)
#label = QtGui.QLabel(self)
#pixmap = QtGui.QPixmap('')
#label.setPixmap(pixmap)
def main():
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
app.exec_()
if __name__ == '__main__':
sys.exit(main())
You need to make your own slot and connect it to the openAction signal.
In your __init__ function do:
openAction.triggered.connect(self.openSlot)
In your class MainWindow define the following function:
def openSlot(self):
# This function is called when the user clicks File->Open.
filename = QtGui.QFileDialog.getOpenFileName()
print(filename)
# Do your pixmap stuff here.

Working with PyQt and Qt designer ui files

I'm new to PyQt and I'm trying to work with ui files directly from within my PyQt script. I have two ui files, mainwindow.ui and landing.ui. Clicking on a button 'pushButton' on the main window should open the landing window. However, clicking on the button does not work as I expected. Here is the code(I'm just trying to work stuff out so the code is pretty rough):
from PyQt4 import QtCore, uic
from PyQt4 import QtGui
import os
CURR = os.path.abspath(os.path.dirname('__file__'))
form_class = uic.loadUiType(os.path.join(CURR, "mainwindow.ui"))[0]
landing_class = uic.loadUiType(os.path.join(CURR, "landing.ui"))[0]
def loadUiWidget(uifilename, parent=None):
uifile = QtCore.QFile(uifilename)
uifile.open(QtCore.QFile.ReadOnly)
ui = uic.loadUi(uifilename)
uifile.close()
return ui
#QtCore.pyqtSlot()
def clicked_slot():
"""this is called when login button is clicked"""
LandingPage = loadUiWidget(os.path.join(CURR, "landing.ui"))
center(LandingPage)
icon(LandingPage)
LandingPage.show()
class MyWindow(QtGui.QMainWindow, form_class):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.pushButton.clicked.connect(clicked_slot)
class LandingPage(QtGui.QMainWindow, landing_class):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
def center(self):
""" Function to center the application
"""
qRect = self.frameGeometry()
centerPoint = QtGui.QDesktopWidget().availableGeometry().center()
qRect.moveCenter(centerPoint)
self.move(qRect.topLeft())
def icon(self):
""" Function to set window icon
"""
appIcon = QtGui.QIcon("icon.png")
self.setWindowIcon(appIcon)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
pixmap = QtGui.QPixmap(os.path.join(CURR, "splash.png"))
splash = QtGui.QSplashScreen(pixmap)
splash.show()
app.processEvents()
MainWindow = MyWindow(None)
center(MainWindow)
icon(MainWindow)
MainWindow.show()
splash.finish(MainWindow)
sys.exit(app.exec_())
What mistake I'm I making??
There are two main problems with your script: firstly, you are not constructing the path to the ui files correctly; and secondly, you are not keeping a reference to the landing-page window (and so it will get garbage-collected immediately after it is shown).
Here is how the part of the script that loads the ui files should be structured:
import os
from PyQt4 import QtCore, QtGui, uic
# get the directory of this script
path = os.path.dirname(os.path.abspath(__file__))
MainWindowUI, MainWindowBase = uic.loadUiType(
os.path.join(path, 'mainwindow.ui'))
LandingPageUI, LandingPageBase = uic.loadUiType(
os.path.join(path, 'landing.ui'))
class MainWindow(MainWindowBase, MainWindowUI):
def __init__(self, parent=None):
MainWindowBase.__init__(self, parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.handleButton)
def handleButton(self):
# keep a reference to the landing page
self.landing = LandingPage()
self.landing.show()
class LandingPage(LandingPageBase, LandingPageUI):
def __init__(self, parent=None):
LandingPageBase.__init__(self, parent)
self.setupUi(self)

Categories