PyQt5中QWebEngineView.loadFinished触发后如何等待JS脚本执行完成
问题原因
你之前的QTimer写法逻辑错误,是把loadFinished的绑定动作延迟了2秒,而不是在loadFinished触发后再延迟执行打印PDF的逻辑。
方案1:loadFinished触发后固定延迟执行打印
直接在emit_pdf函数里启动单次QTimer,等指定时间后再调用printToPdf即可,代码如下:
import sys from PyQt5 import QtWidgets, QtWebEngineWidgets, QtCore app = QtWidgets.QApplication(sys.argv) loader = QtWebEngineWidgets.QWebEngineView() loader.setZoomFactor(1) loader.page().pdfPrintingFinished.connect(loader.close) url = "你的目标页面地址" loader.load(QtCore.QUrl(url)) def emit_pdf(finished): # 页面加载完成后延迟3秒执行打印,可按需调整时长 QtCore.QTimer.singleShot(3000, lambda: loader.page().printToPdf("test.pdf")) loader.loadFinished.connect(emit_pdf) app.exec()
该方案简单直接,适合你可以确定JS执行最大耗时的场景,缺点是延迟时长固定,要么浪费不必要的等待时间,要么时长不足还是无法获取完整内容。
方案2:JS执行完成后主动触发打印(更优)
该方案不需要盲等固定时长,页面JS逻辑执行完成就立刻触发打印,准确率更高、耗时更短。
实现逻辑是给QWebEnginePage注册PyQt端的回调函数,页面JS在所有逻辑执行完成后调用该回调,触发PDF打印。
PyQt端代码
import sys from PyQt5 import QtWidgets, QtWebEngineWidgets, QtCore, QtWebChannel class PrintPage(QtWebEngineWidgets.QWebEnginePage): js_finished = QtCore.pyqtSignal() def __init__(self, parent=None): super().__init__(parent) # 注册桥接对象给JS端调用 self.setWebChannel(QtWebChannel.QWebChannel()) self.webChannel().registerObject("pyBridge", self) self.js_finished.connect(self.print_pdf) @QtCore.pyqtSlot() def onJsFinished(self): # 接收JS端的完成通知,触发打印信号 self.js_finished.emit() def print_pdf(self): self.printToPdf("test.pdf") app = QtWidgets.QApplication(sys.argv) loader = QtWebEngineWidgets.QWebEngineView() page = PrintPage() loader.setPage(page) loader.setZoomFactor(1) loader.page().pdfPrintingFinished.connect(loader.close) url = "你的目标页面地址" loader.load(QtCore.QUrl(url)) app.exec()
HTML/JS端补充代码
在你的HTML页面所有JS业务逻辑执行完成的位置,添加一行调用即可:
// 所有JS逻辑执行完后调用该方法通知PyQt端 window.pyBridge.onJsFinished()
如果目标HTML不可修改,无法插入JS代码,可以替换为定时查询页面DOM状态判断JS是否执行完成:
def emit_pdf(finished): def check_page_state(): # 自定义JS判断逻辑,示例为判断目标元素是否已渲染 loader.page().runJavaScript( "document.querySelector('#你需要的目标元素ID') != null", lambda res: res and loader.page().printToPdf("test.pdf") ) # 每500ms检查一次页面状态,直到满足打印条件 timer = QtCore.QTimer() timer.timeout.connect(check_page_state) timer.start(500)
内容的提问来源于stack exchange,提问作者Ozgur O.
相关产品推荐
相关产品推荐

