Reputation: 38
I'm trying to print a PDF from website using Tkcalendar and PyQt5 in Python 3.8.5 for Windows 10
I can print a PDF file on the first attempt. But I can't print again because Tkcalendar closes, and I want to keep it open. What am I doing wrong?
Thanks.
import datetime
import requests
import re
import sys
from bs4 import BeautifulSoup
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5 import QtWebEngineWidgets
from tkinter import *
from tkinter import messagebox
from tkcalendar import *
def generar_pdf():
fecha = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%Y-%m-%d")
day = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%d")
month = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%m")
year = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%Y")
strURL = "https://www.dof.gob.mx/index_111.php?year=" + year + "&month=" + month + "&day=" + day + "&edicion=MAT"
req = requests.get(strURL)
soup = BeautifulSoup(req.text, "lxml")
for sub_heading in soup.find_all("a", href=True):
if re.sub("[^\w .]", "", sub_heading.text) == "Tipo de cambio para solventar obligaciones denominadas en moneda extranjera pagaderas en la República Mexicana.":
DOF_URL = "https://www.dof.gob.mx" + sub_heading.get("href")
else:
pass
app = QtWidgets.QApplication(sys.argv)
loader = QtWebEngineWidgets.QWebEngineView()
loader.page().pdfPrintingFinished.connect(loader.close)
loader.load(QtCore.QUrl(DOF_URL))
def emit_pdf(finished):
loader.page().printToPdf(fecha + ".pdf")
messagebox.showinfo("PDF Generado", "Se generó el PDF con éxito.")
loader.loadFinished.connect(emit_pdf)
app.exec()
root = Tk()
root.geometry("400x400")
fecha_hoy = datetime.datetime.now()
dia_hoy = int(fecha_hoy.strftime("%d"))
mes_hoy = int(fecha_hoy.strftime("%m"))
año_hoy = int(fecha_hoy.strftime("%Y"))
cal = Calendar(root, selectmode="day", year=año_hoy, month=mes_hoy, day=dia_hoy, date_pattern="dd-mm-yyyy")
cal.pack(pady=20, fill="both", expand=True)
my_button = Button(cal, text="Generar PDF", command=generar_pdf)
my_button.pack(pady=20)
root.mainloop()
Upvotes: 1
Views: 192
Reputation: 244369
The problem is that you are using 2 libraries that have 2 eventloops, a possible solution is to run the eventloops separately in different processes but that is unnecessarily complicating the application. A better solution is to write all the logic using a single library, in this one because there is no equivalent of Qt WebEngine in tkinter I will choose to use pyqt5:
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
SCRIPT_FIND_URL = """
var url = ""
var phrase = "Tipo de cambio para solventar obligaciones denominadas en moneda extranjera pagaderas en la República Mexicana."
var elements = document.getElementsByTagName("a");
for(const e of elements){
if(e.text.includes(phrase))
url = e.href
}
url
"""
class PageOffline(QtWebEngineWidgets.QWebEnginePage):
finished = QtCore.pyqtSignal(bool)
def __init__(self, parent=None):
super().__init__(parent)
self.date_url = QtCore.QUrl()
self.loadFinished.connect(self.handle_loaded)
self.pdfPrintingFinished.connect(self.handle_pdf)
def search(self, date):
self.date = date
self.date_url = QtCore.QUrl("https://www.dof.gob.mx/index_111.php")
query = QtCore.QUrlQuery()
query.addQueryItem("year", self.date.toString("yyyy"))
query.addQueryItem("month", self.date.toString("MM"))
query.addQueryItem("day", self.date.toString("dd"))
query.addQueryItem("edicion", "MAT")
self.date_url.setQuery(query)
self.load(self.date_url)
def handle_loaded(self, ok):
if ok:
if self.url() == self.date_url:
self.runJavaScript(SCRIPT_FIND_URL, self.handle_url)
else:
filename = "{}.pdf".format(self.date.toString("yyyy-MM-dd"))
self.printToPdf(filename)
else:
self.finished.emit(False)
def handle_url(self, url):
if url:
pdf_url = QtCore.QUrl.fromUserInput(url)
self.load(pdf_url)
else:
self.finished.emit(False)
def handle_pdf(self, path, ok):
self.finished.emit(ok)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.page = PageOffline()
self.button = QtWidgets.QPushButton("Generate pdf")
self.calendar = QtWidgets.QCalendarWidget()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.calendar)
lay.addWidget(self.button, alignment=QtCore.Qt.AlignCenter)
self.button.clicked.connect(self.handle_clicked)
self.page.finished.connect(self.handle_print_finished)
def handle_clicked(self):
date = self.calendar.selectedDate()
self.page.search(date)
self.button.setEnabled(False)
def handle_print_finished(self, status):
QtWidgets.QMessageBox.information(
self,
"Generación de PDF",
"El PDF fue generado con éxito" if status else "La generación de PDF fallo",
)
self.button.setEnabled(True)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.Spanish))
w = Widget()
w.resize(400, 400)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Upvotes: 1