欢迎光临
我们一直在努力

Python 文件解析: Excel / Word / PDF 的解析、处理、预览与下载

1. 总览:同一个入口,不同解析器

当用户上传文件时,技术链路通常是:

  • 接收文件并保存原件。
  • 按扩展名选择对应的 Python 解析函数。
  • 生成可预览数据。
  • 前端展示原件与解析结果。
  • 用户编辑后保存。
  • 提供原件下载与编辑结果下载。
  • #mermaid-svg-EXUIk8R5msHwbgOx{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EXUIk8R5msHwbgOx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EXUIk8R5msHwbgOx .error-icon{fill:#552222;}#mermaid-svg-EXUIk8R5msHwbgOx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EXUIk8R5msHwbgOx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EXUIk8R5msHwbgOx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EXUIk8R5msHwbgOx .marker.cross{stroke:#333333;}#mermaid-svg-EXUIk8R5msHwbgOx svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EXUIk8R5msHwbgOx p{margin:0;}#mermaid-svg-EXUIk8R5msHwbgOx .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-EXUIk8R5msHwbgOx .cluster-label text{fill:#333;}#mermaid-svg-EXUIk8R5msHwbgOx .cluster-label span{color:#333;}#mermaid-svg-EXUIk8R5msHwbgOx .cluster-label span p{background-color:transparent;}#mermaid-svg-EXUIk8R5msHwbgOx .label text,#mermaid-svg-EXUIk8R5msHwbgOx span{fill:#333;color:#333;}#mermaid-svg-EXUIk8R5msHwbgOx .node rect,#mermaid-svg-EXUIk8R5msHwbgOx .node circle,#mermaid-svg-EXUIk8R5msHwbgOx .node ellipse,#mermaid-svg-EXUIk8R5msHwbgOx .node polygon,#mermaid-svg-EXUIk8R5msHwbgOx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EXUIk8R5msHwbgOx .rough-node .label text,#mermaid-svg-EXUIk8R5msHwbgOx .node .label text,#mermaid-svg-EXUIk8R5msHwbgOx .image-shape .label,#mermaid-svg-EXUIk8R5msHwbgOx .icon-shape .label{text-anchor:middle;}#mermaid-svg-EXUIk8R5msHwbgOx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EXUIk8R5msHwbgOx .rough-node .label,#mermaid-svg-EXUIk8R5msHwbgOx .node .label,#mermaid-svg-EXUIk8R5msHwbgOx .image-shape .label,#mermaid-svg-EXUIk8R5msHwbgOx .icon-shape .label{text-align:center;}#mermaid-svg-EXUIk8R5msHwbgOx .node.clickable{cursor:pointer;}#mermaid-svg-EXUIk8R5msHwbgOx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EXUIk8R5msHwbgOx .arrowheadPath{fill:#333333;}#mermaid-svg-EXUIk8R5msHwbgOx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EXUIk8R5msHwbgOx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EXUIk8R5msHwbgOx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EXUIk8R5msHwbgOx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EXUIk8R5msHwbgOx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EXUIk8R5msHwbgOx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EXUIk8R5msHwbgOx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EXUIk8R5msHwbgOx .cluster text{fill:#333;}#mermaid-svg-EXUIk8R5msHwbgOx .cluster span{color:#333;}#mermaid-svg-EXUIk8R5msHwbgOx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EXUIk8R5msHwbgOx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EXUIk8R5msHwbgOx rect.text{fill:none;stroke-width:0;}#mermaid-svg-EXUIk8R5msHwbgOx .icon-shape,#mermaid-svg-EXUIk8R5msHwbgOx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EXUIk8R5msHwbgOx .icon-shape p,#mermaid-svg-EXUIk8R5msHwbgOx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EXUIk8R5msHwbgOx .icon-shape rect,#mermaid-svg-EXUIk8R5msHwbgOx .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EXUIk8R5msHwbgOx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EXUIk8R5msHwbgOx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EXUIk8R5msHwbgOx :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    xlsx

    docx

    pdf

    用户上传文件

    Upload API

    保存原件

    按扩展名路由

    Excel 处理器

    Word 处理器

    PDF 处理器

    预览数据

    预览数据

    预览数据

    前端预览与编辑

    保存编辑结果

    下载原件 / 下载编辑结果


    2. 插件与依赖清单

    先统一约定:本文里“插件”指第三方依赖包(Python 包 / 前端 npm 包)。

    2.1 Python 端插件(后端)

    插件版本(示例)用途是否必须
    fastapi 0.111.0 提供上传、预览、保存、下载 API 必须
    uvicorn 0.29.0 启动 FastAPI 服务 必须
    python-multipart 0.0.9 支持 multipart/form-data 文件上传 必须
    openpyxl 3.1.2 解析/回写 Excel(xlsx) Excel 必须
    pandas 2.2.2 Excel/表格辅助清洗(可选但常用) 推荐
    python-docx 1.1.0 解析/生成 Word(docx) Word 必须
    pymupdf (fitz) 1.24.9 PDF 文本、表格、分页信息提取 PDF 必须

    对应 import 写法(便于直接复制代码):

  • from fastapi import FastAPI, UploadFile, File
  • from openpyxl import load_workbook
  • from docx import Document
  • import fitz(来自 pymupdf)
  • 2.2 前端插件(预览与编辑)

    插件版本(示例)用途是否必须
    xlsx ^0.18.5 浏览器端 Excel 预览(按 sheet 渲染) Excel 预览必须
    mammoth ^1.11.0 浏览器端 Word 转 HTML 预览 Word 预览必须
    react-data-grid 7.0.0-beta.59 表格编辑组件(Excel/Word 表格/PDF 表格修订) 需要编辑时必须

    2.3 可选插件(PDF OCR 兜底)

    插件用途是否必须
    pytesseract + Pillow PDF/图片 OCR 兜底 可选
    paddleocr 中文 OCR 兜底(效果通常更好) 可选

    2.4 可选插件(兼容旧格式)

    插件/工具用途是否必须
    xlrd 仅当你要直接读取 .xls 时使用 可选
    libreoffice (soffice) 把 .doc 转成 .docx,再交给 python-docx 解析 可选

    2.5 安装命令示例

    # Backend
    pip install fastapi uvicorn python-multipart openpyxl pandas python-docx pymupdf

    # Frontend
    npm install xlsx mammoth react-data-grid

    # Optional OCR fallback
    pip install pytesseract pillow
    # or
    pip install paddleocr

    # Optional legacy-format support
    pip install xlrd


    3. 通用基础:上传、存储、路由

    3.1 上传接口示例

    from pathlib import Path
    from fastapi import APIRouter, UploadFile, File

    router = APIRouter()

    @router.post("/api/files/upload")
    async def upload(files: list[UploadFile] = File(...)):
    items = []
    for f in files:
    suffix = Path(f.filename).suffix.lower()
    raw_path = save_raw_file(f) # 保存原件

    if suffix == ".xlsx":
    file_id = process_excel(raw_path)
    file_type = "excel"
    elif suffix == ".docx":
    file_id = process_word(raw_path)
    file_type = "word"
    elif suffix == ".pdf":
    file_id = process_pdf(raw_path)
    file_type = "pdf"
    else:
    items.append({"filename": f.filename, "error": "unsupported file type"})
    continue

    items.append({"file_id": file_id, "type": file_type, "filename": f.filename})

    return {"items": items}

    说明:openpyxl 主流场景是 .xlsx,python-docx 主流场景是 .docx。
    如果必须支持 .xls / .doc,建议先做“格式转换”再进入本文解析流水线。

    3.2 原件下载接口(通用)

    from fastapi.responses import FileResponse

    @router.get("/api/files/{file_id}/download/raw")
    def download_raw(file_id: str):
    path = locate_raw_file(file_id)
    return FileResponse(path, filename=path.name)


    4. Excel:解析、处理、预览、编辑保存、下载

    本章用到的插件:openpyxl、pandas(可选)、xlsx、react-data-grid。

    Excel 的特点是天然二维网格,所以处理策略是“保留 sheet + 保留行列”。

    4.1 解析(Python)

    from openpyxl import load_workbook

    def parse_excel(path: str) > dict:
    wb = load_workbook(path, data_only=True)
    sheets: dict[str, list[list[str]]] = {}

    for sheet_name in wb.sheetnames:
    ws = wb[sheet_name]
    rows: list[list[str]] = []
    for row in ws.iter_rows(values_only=True):
    rows.append(["" if c is None else str(c) for c in row])
    sheets[sheet_name] = rows

    return {
    "sheet_names": wb.sheetnames,
    "sheets": sheets,
    }

    4.2 处理(可选)

    常见的通用处理:

  • 去掉尾部空行。
  • 统一行长度(短行补空字符串)。
  • 把非字符串安全转成字符串,避免前端渲染异常。
  • def normalize_excel_rows(rows: list[list[str]]) > list[list[str]]:
    if not rows:
    return [[""]]
    width = max(len(r) for r in rows)
    normalized = []
    for r in rows:
    row = ["" if c is None else str(c) for c in r]
    if len(row) < width:
    row += [""] * (width len(row))
    normalized.append(row[:width])
    return normalized

    4.3 前端预览

    前端展示方式:

  • Sheet 名作为 tab。
  • 当前 sheet 用 table 或 DataGrid 渲染。
  • 支持切换 sheet。
  • 4.4 编辑保存

    PUT /api/excel/{file_id}/edit

    {
    "sheet_name": "Sheet1",
    "rows": [["A1", "B1"], ["A2", "B2"]]
    }

    后端可把编辑结果保存成:

  • excel_edits.json(便于二次编辑)。
  • edited.xlsx(便于下载)。
  • 4.5 下载

  • 原件:GET /api/excel/{file_id}/download/raw
  • 编辑版:GET /api/excel/{file_id}/download/edited
  • @router.get("/api/excel/{file_id}/download/edited")
    def download_excel_edited(file_id: str):
    edited_path = build_edited_excel(file_id) # 根据保存的 rows 重建 xlsx
    return FileResponse(edited_path, filename=edited_path.name)

    存储后端前端用户存储后端前端用户#mermaid-svg-MwyRjjL0o67weGPg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MwyRjjL0o67weGPg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MwyRjjL0o67weGPg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MwyRjjL0o67weGPg .error-icon{fill:#552222;}#mermaid-svg-MwyRjjL0o67weGPg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MwyRjjL0o67weGPg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MwyRjjL0o67weGPg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MwyRjjL0o67weGPg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MwyRjjL0o67weGPg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MwyRjjL0o67weGPg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MwyRjjL0o67weGPg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MwyRjjL0o67weGPg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MwyRjjL0o67weGPg .marker.cross{stroke:#333333;}#mermaid-svg-MwyRjjL0o67weGPg svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MwyRjjL0o67weGPg p{margin:0;}#mermaid-svg-MwyRjjL0o67weGPg .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MwyRjjL0o67weGPg text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-MwyRjjL0o67weGPg .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MwyRjjL0o67weGPg .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-MwyRjjL0o67weGPg .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-MwyRjjL0o67weGPg .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-MwyRjjL0o67weGPg #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-MwyRjjL0o67weGPg .sequenceNumber{fill:white;}#mermaid-svg-MwyRjjL0o67weGPg #sequencenumber{fill:#333;}#mermaid-svg-MwyRjjL0o67weGPg #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-MwyRjjL0o67weGPg .messageText{fill:#333;stroke:none;}#mermaid-svg-MwyRjjL0o67weGPg .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MwyRjjL0o67weGPg .labelText,#mermaid-svg-MwyRjjL0o67weGPg .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-MwyRjjL0o67weGPg .loopText,#mermaid-svg-MwyRjjL0o67weGPg .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-MwyRjjL0o67weGPg .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MwyRjjL0o67weGPg .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-MwyRjjL0o67weGPg .noteText,#mermaid-svg-MwyRjjL0o67weGPg .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-MwyRjjL0o67weGPg .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MwyRjjL0o67weGPg .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MwyRjjL0o67weGPg .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MwyRjjL0o67weGPg .actorPopupMenu{position:absolute;}#mermaid-svg-MwyRjjL0o67weGPg .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-MwyRjjL0o67weGPg .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MwyRjjL0o67weGPg .actor-man circle,#mermaid-svg-MwyRjjL0o67weGPg line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-MwyRjjL0o67weGPg :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}上传 ExcelPOST /upload保存 raw.xlsxparse_excelsheet_names + sheets编辑单元格PUT /excel/{file_id}/edit保存 excel_edits.json / edited.xlsx下载编辑版GET /excel/{file_id}/download/editededited.xlsx


    5. Word:解析、处理、预览、编辑保存、下载

    本章用到的插件:python-docx、mammoth、react-data-grid。

    Word 的天然结构是“段落 + 表格”,不建议简单压平为纯二维表。

    5.1 解析(Python)

    from docx import Document

    def parse_word(path: str) > dict:
    doc = Document(path)
    blocks: list[dict] = []

    # 段落块
    for p in doc.paragraphs:
    text = p.text.strip()
    if text:
    blocks.append({"type": "paragraph", "text": text})

    # 表格块
    for table_index, table in enumerate(doc.tables):
    rows = []
    for row in table.rows:
    rows.append([cell.text.strip() for cell in row.cells])
    blocks.append({"type": "table", "table_index": table_index, "rows": rows})

    return {"blocks": blocks}

    5.2 处理(可选)

  • 清理连续空段落。
  • 表格行列补齐。
  • 对超长文本做安全截断(仅显示时,不改原文)。
  • 5.3 前端预览

    Word 常见做法是双视图:

  • 原件预览:mammoth 转 HTML,阅读体验更接近原文档。
  • 编辑视图:
  • 段落块用文本编辑器。
  • 表格块用 DataGrid。
  • 5.4 编辑保存

    PUT /api/word/{file_id}/edit

    {
    "blocks": [
    {"type": "paragraph", "text": "Updated paragraph"},
    {"type": "table", "table_index": 0, "rows": [["Header1", "Header2"], ["V1", "V2"]]}
    ]
    }

    后端可以:

  • 保存 word_edits.json。
  • 用 python-docx 生成 edited.docx。
  • 5.5 下载

  • 原件:GET /api/word/{file_id}/download/raw
  • 编辑版:GET /api/word/{file_id}/download/edited
  • @router.get("/api/word/{file_id}/download/edited")
    def download_word_edited(file_id: str):
    edited_docx = build_edited_word_docx(file_id)
    return FileResponse(edited_docx, filename=edited_docx.name)


    6. PDF:解析、处理、预览、编辑保存、下载

    本章用到的插件:pymupdf(可选 OCR:pytesseract/paddleocr)、react-data-grid。

    PDF 的关键是“按页处理”,因为页面是它的天然单位。

    6.1 解析(Python)

    import fitz

    def parse_pdf(path: str) > dict:
    pages = []
    with fitz.open(path) as doc:
    for i in range(doc.page_count):
    page = doc.load_page(i)
    text = page.get_text("text") or ""

    tables = []
    finder = page.find_tables()
    if finder and finder.tables:
    for t in finder.tables:
    tables.append([[str(c or "").strip() for c in row] for row in t.extract()])

    pages.append({
    "page_no": i + 1,
    "text": text,
    "tables": tables,
    "width": float(page.rect.width),
    "height": float(page.rect.height),
    })

    return {"page_count": len(pages), "pages": pages}

    6.2 处理(可选)

  • 当 find_tables() 抽不到表时,回退到 page.get_text("words") 做词块聚合。
  • 对文本进行页级摘要(便于快速预览)。
  • 对识别结果增加 warnings 字段(纯技术提示)。
  • 6.3 前端预览

    建议双层:

  • 原件:iframe/objectURL 直接预览 PDF。
  • 解析结果:按页展示 text + tables。
  • 6.4 编辑保存

    PUT /api/pdf/{file_id}/edit

    {
    "page_no": 1,
    "table_index": 0,
    "rows": [["Col1", "Col2"], ["A", "B"]],
    "notes": "manual correction"
    }

    后端可保存:

  • pdf_edits.json
  • edited.pdf(可选实现:加批注页、嵌入修订信息)
  • 6.5 下载

  • 原件:GET /api/pdf/{file_id}/download/raw
  • 编辑版 PDF:GET /api/pdf/{file_id}/download/edited
  • 编辑记录 JSON(可选):GET /api/pdf/{file_id}/download/edits-json
  • 存储后端前端用户存储后端前端用户#mermaid-svg-fJ1lmYaePWYry9p8{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fJ1lmYaePWYry9p8 .error-icon{fill:#552222;}#mermaid-svg-fJ1lmYaePWYry9p8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fJ1lmYaePWYry9p8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fJ1lmYaePWYry9p8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fJ1lmYaePWYry9p8 .marker.cross{stroke:#333333;}#mermaid-svg-fJ1lmYaePWYry9p8 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fJ1lmYaePWYry9p8 p{margin:0;}#mermaid-svg-fJ1lmYaePWYry9p8 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fJ1lmYaePWYry9p8 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fJ1lmYaePWYry9p8 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-fJ1lmYaePWYry9p8 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-fJ1lmYaePWYry9p8 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-fJ1lmYaePWYry9p8 .sequenceNumber{fill:white;}#mermaid-svg-fJ1lmYaePWYry9p8 #sequencenumber{fill:#333;}#mermaid-svg-fJ1lmYaePWYry9p8 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-fJ1lmYaePWYry9p8 .messageText{fill:#333;stroke:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fJ1lmYaePWYry9p8 .labelText,#mermaid-svg-fJ1lmYaePWYry9p8 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .loopText,#mermaid-svg-fJ1lmYaePWYry9p8 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fJ1lmYaePWYry9p8 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-fJ1lmYaePWYry9p8 .noteText,#mermaid-svg-fJ1lmYaePWYry9p8 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-fJ1lmYaePWYry9p8 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fJ1lmYaePWYry9p8 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fJ1lmYaePWYry9p8 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fJ1lmYaePWYry9p8 .actorPopupMenu{position:absolute;}#mermaid-svg-fJ1lmYaePWYry9p8 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-fJ1lmYaePWYry9p8 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fJ1lmYaePWYry9p8 .actor-man circle,#mermaid-svg-fJ1lmYaePWYry9p8 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-fJ1lmYaePWYry9p8 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}上传 PDFPOST /upload保存 raw.pdfparse_pdf(分页提取)pages/meta修订表格PUT /pdf/{file_id}/edit保存 pdf_edits.json / edited.pdf下载编辑版GET /pdf/{file_id}/download/editededited.pdf


    7. API 清单(示例)

    类型预览接口保存接口下载接口
    Excel GET /api/excel/{file_id}/preview PUT /api/excel/{file_id}/edit download/raw / download/edited
    Word GET /api/word/{file_id}/preview PUT /api/word/{file_id}/edit download/raw / download/edited
    PDF GET /api/pdf/{file_id}/preview PUT /api/pdf/{file_id}/edit download/raw / download/edited

    说明:这三组接口可以由同一个服务实现。本文拆开写,仅用于按文件格式独立说明技术实现细节。


    8. 工程落地建议(纯技术)

  • 原件一定要保存,不要只存解析结果。
  • 编辑结果建议落 JSON,再按需导出编辑版文件。
  • 下载接口统一加 Content-Disposition: attachment。
  • 所有预览数据都做空值与类型兜底,前端会省很多判断。
  • 文件名建议带时间戳,例如:
  • report_edited_20260224_1530.xlsx
  • doc_edited_20260224_1530.docx
  • scan_edited_20260224_1530.pdf

  • 9. 效果

    excel预览效果

    excel预览效果

    word预览效果

    word预览效果

    pdf 预览效果

    pdf 预览效果

    赞(0)
    未经允许不得转载:171主机测评 » Python 文件解析: Excel / Word / PDF 的解析、处理、预览与下载
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址