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

如何捕获PyMuPDF调用MuPDF时返回的C层错误并汇总异常文件?

解决PyMuPDF(fitz)底层C层错误捕获及问题文件汇总

问题场景

使用fitz(PyMuPDF)提取PDF内容并保存为JSON时,程序运行过程中会输出底层C库的语法错误提示(如MuPDF error: syntax error: unknown keyword: '41r020I'),程序不会终止,但部分生成的JSON存在乱码,需要捕获这些错误并汇总所有存在潜在问题的文件。

解决方案

由于这些错误是MuPDF C层直接输出到标准错误流(stderr)的,Python常规try-except无法捕获,因此需要通过重定向stderr的方式收集错误信息,再结合业务逻辑汇总问题文件。

1. 导入必要模块

添加sys和io模块实现stderr重定向:

import sys
import io

2. 修改核心提取函数

更新mu_get_content_from函数,加入stderr捕获逻辑,检测C层错误输出并标记问题文件:

def mu_get_content_from(folder_name, file_name):
    src_file_path = os.path.join(os.getcwd(), "To Do PDF", folder_name, f"{file_name}.pdf")
    dst_file_path = os.path.join(os.getcwd(), "pdfs-2-texts", folder_name, f"{file_name}.json")

    os.makedirs(os.path.dirname(dst_file_path), exist_ok=True)

    # 临时重定向stderr到内存缓冲区
    old_stderr = sys.stderr
    sys.stderr = io.StringIO()
    
    doc = None
    total_pages = 0
    content = ""
    has_mupdf_error = False

    try:
        doc = fitz.open(src_file_path)
        for page in doc:
            # 处理页面前清空缓冲区,避免跨页错误累积
            sys.stderr.seek(0)
            sys.stderr.truncate(0)
            
            page_content = page.get_text()
            
            # 检查当前页是否触发C层错误
            stderr_output = sys.stderr.getvalue()
            if stderr_output and "MuPDF error" in stderr_output:
                has_mupdf_error = True
            
            if not page_content:
                continue

            page_content = page_content.strip()
            total_pages += 1

            if page_content.endswith('.'):
                content += "\n\n" + page_content
            else:
                content += " " + page_content
    finally:
        if doc:
            doc.close()
        # 恢复原有stderr
        sys.stderr = old_stderr

    # 标记内容为空或触发MuPDF错误的文件
    if content.strip() == "" or has_mupdf_error:
        error_files.append((folder_name, file_name))

    save_dict = {
        "Title": file_name,
        "Pages": total_pages,
        "Content": content
    }

    with open(dst_file_path, 'w', encoding='utf-8') as fo:
        json.dump(save_dict, fo, ensure_ascii=False, indent=4)

    return True

3. 遍历管道与错误汇总

原有遍历逻辑保持不变,程序结束后输出所有问题文件:

# 初始化错误文件列表
error_files = []

for folder in folders:
    folder_path = os.path.join(os.getcwd(), "To Do PDF", folder)
    files = get_file_names(folder_path)
    for file in tqdm(files):
        print(file)
        file_name, ext = os.path.splitext(file)
        if ext.lower() != ".pdf":
            error_files.append((folder, file_name))
            continue
        mu_get_content_from(folder, file_name)

# 输出所有问题文件
print("\n存在问题的文件列表:")
for folder, fname in error_files:
    print(f"文件夹:{folder},文件:{fname}.pdf")

关键说明

  • 通过io.StringIO()临时接管stderr,捕获C层输出的错误信息
  • 每次处理页面时清空缓冲区,确保错误信息对应当前PDF页
  • 结合内容为空判断和C层错误标记,统一汇总问题文件
  • 操作完成后恢复原有stderr,不影响后续程序错误输出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 23:29:57