1

我正在尝试在适用于 Windows 10 的 Python 3.8.5 中使用 Tkcalendar 和 PyQt5 从网站打印 PDF

我可以在第一次尝试时打印 PDF 文件。但我无法再次打印,因为 Tkcalendar 关闭了,我想保持打开状态。我究竟做错了什么?

谢谢。

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()

4

1 回答 1

1

问题是您正在使用具有 2 个事件循环的 2 个库,一个可能的解决方案是在不同的进程中分别运行事件循环,但这会不必要地使应用程序复杂化。更好的解决方案是使用单个库编写所有逻辑,在这个库中,因为在 tkinter 中没有等效的 Qt WebEngine 我将选择使用 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()
于 2020-08-10T05:30:07.830 回答