You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python批量保存网页为PDF问题求助(PyQt5/wkhtmltopdf)

批量将网页保存为PDF的解决方案

问题分析

你的代码核心问题在于:

  • 每次调用save_webpage_as_pdf时,pdfPrintingFinished信号直接绑定了QApplication.exit(),导致第一个网页转换完成后程序立即退出,后续任务完全无法执行。
  • 循环中一次性创建多个QWebEngineView实例,Qt事件循环无法正确处理多异步加载/打印任务,容易出现资源冲突或任务中断。

改进后的PyQt5方案

改用任务队列串行处理,完成一个网页转换后再启动下一个,避免提前退出程序:

import requests
from bs4 import BeautifulSoup
import sys
from PyQt5 import QtWidgets, QtWebEngineWidgets
from PyQt5.QtCore import QUrl, QObject
from PyQt5.QtGui import QPageLayout, QPageSize
from pathlib import Path

class PDFConverter(QObject):
    def __init__(self, url_queue):
        super().__init__()
        self.url_queue = url_queue
        self.loader = QtWebEngineWidgets.QWebEngineView()
        self.loader.setZoomFactor(1)
        self.layout = QPageLayout()
        self.layout.setPageSize(QPageSize(QPageSize.A4Extra))
        self.layout.setOrientation(QPageLayout.Portrait)
        # 打印完成后触发下一个任务
        self.loader.page().pdfPrintingFinished.connect(self.process_next_task)
        self.loader.loadFinished.connect(self.print_pdf)

    def start(self):
        # 启动首个任务
        self.process_next_task()

    def process_next_task(self):
        if self.url_queue:
            url, output_file = self.url_queue.pop(0)
            if not Path(output_file).is_file():
                self.current_output = output_file
                self.loader.load(QUrl(url))
            else:
                # 文件已存在,直接跳过
                self.process_next_task()
        else:
            # 所有任务完成后再退出
            QtWidgets.QApplication.exit()

    def print_pdf(self, finished):
        if finished:
            self.loader.page().printToPdf(self.current_output, pageLayout=self.layout)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    # 爬取目标网页列表
    catalogue_url = "https://debis.deu.edu.tr/ders-katalog/2023-2024/tr/"
    department_url = "bolum_1129_tr.html"
    reqs = requests.get(catalogue_url + department_url)
    content = reqs.content.decode('utf-8')
    soup = BeautifulSoup(content, 'html.parser')

    urls = soup.find_all('a')
    start_index = [url.get('href') for url in urls].index("../havuz/1129tr.pdf")
    end_index = [url.get('href') for url in urls].index("bolum_1129_tr.html")

    # 构建任务队列:[(目标URL, 输出文件名), ...]
    task_queue = []
    for i in range(start_index + 1, end_index):
        course_url = catalogue_url + urls[i].get('href')
        output_file = f"File({i}).pdf"
        task_queue.append((course_url, output_file))
        print(f"待处理:{course_url} -> {output_file}")

    # 启动转换器
    converter = PDFConverter(task_queue)
    converter.start()

    sys.exit(app.exec_())

改进点说明

  • 用PDFConverter类统一管理任务队列,串行处理每个网页,避免多实例资源冲突。
  • 仅在所有任务完成后才退出应用,保证所有转换任务执行完毕。
  • 自动跳过已存在的PDF文件,避免重复转换。

替代方案:使用Playwright(更简单稳定)

如果PyQt5的配置仍有问题,推荐使用Playwright,它对网页渲染和PDF转换的支持更友好,逻辑更直观:

步骤1:安装依赖

pip install playwright
playwright install chromium

步骤2:批量转换代码

import requests
from bs4 import BeautifulSoup
from playwright.sync_api import sync_playwright
from pathlib import Path

# 爬取目标网页列表
catalogue_url = "https://debis.deu.edu.tr/ders-katalog/2023-2024/tr/"
department_url = "bolum_1129_tr.html"
reqs = requests.get(catalogue_url + department_url)
content = reqs.content.decode('utf-8')
soup = BeautifulSoup(content, 'html.parser')

urls = soup.find_all('a')
start_index = [url.get('href') for url in urls].index("../havuz/1129tr.pdf")
end_index = [url.get('href') for url in urls].index("bolum_1129_tr.html")

# 批量转换
with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.set_viewport_size({"width": 1280, "height": 720})
    
    for i in range(start_index + 1, end_index):
        course_url = catalogue_url + urls[i].get('href')
        output_file = f"File({i}).pdf"
        
        if not Path(output_file).is_file():
            print(f"转换中:{course_url}")
            # 等待网页完全加载后再生成PDF
            page.goto(course_url, wait_until="networkidle")
            page.pdf(
                path=output_file,
                format="A4",
                print_background=True
            )
        else:
            print(f"文件已存在,跳过:{output_file}")
    
    browser.close()

优势

  • 无需处理Qt事件循环的异步问题,代码逻辑更简洁。
  • 支持等待网页完全加载(wait_until="networkidle"),避免内容未加载完全就生成PDF。
  • 自动处理页面样式、图片等资源加载,转换效果更稳定。

内容的提问来源于stack exchange,提问作者bkarpuz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:05:11