当前位置: 首页 > news >正文

RAG 文件解析:PDF / Word / Excel / HTML 全格式文本提取

引言

你想搭一个知识库,让 AI 能基于你的文档来回答问题(RAG)。第一步是什么?

不是选向量数据库,不是调 Embedding 模型——第一步是把文件变成纯文本

听起来简单,但实际做的时候坑多:PDF 里的表格解析出来全是乱的、Word 的嵌套样式丢失关键信息、Excel 合并单元格一团糟、HTML 满屏广告混在正文里……

今天的目标:用 Python 实现一个统一的FileParser类,传入任意 PDF / Word / Excel / HTML 文件,输出结构化的纯文本


为什么文件解析是 RAG 的第一关

RAG 的完整链路:

文件 → 解析成文本 → 切片 → Embedding → 存入向量库 → 检索 → 喂给 LLM → 生成回答

解析质量决定了后面每一步的上限。garbage in,garbage out。

格式解析难度
PDF★★★★★(最难,本质是排版描述文件)
Word (.docx)★★★
Excel (.xlsx)★★★
HTML★★

统一输出格式

先定义统一结构,不管什么格式进来,出来的数据结构一致:

@dataclassclass ParsedDocument: filename: str content: str # 合并后的全文纯文本 file_type: str # pdf / docx / xlsx / html metadata: dict pages: list[str] # 按页/sheet 分隔的文本列表

pages字段很重要——后续切片时可以用页码信息做定位,回答时能告诉用户"来源:第 3 页"。


PDF 解析

工具选型PyMuPDF作为主力,pdfplumber处理表格。

pip install PyMuPDF pdfplumber

基础文本提取(PyMuPDF)

import fitzdef parse_pdf(filepath: str) -> ParsedDocument: doc = fitz.open(filepath) pages = [] for page in doc: text = page.get_text("text").strip() if text: pages.append(text) doc.close() return ParsedDocument( filename=filepath.split("/")[-1], content="\n\n".join(pages), file_type="pdf", metadata={"page_count": len(pages)}, pages=pages, )

表格提取(pdfplumber)

纯文字提取碰到表格会变成一堆错位文字,pdfplumber 能识别表格结构,并转成 Markdown 格式:

def table_to_markdown(table: list[list]) -> str: cleaned = [[str(cell) if cell else "" for cell in row] for row in table] header = "| " + " | ".join(cleaned[0]) + " |" separator = "| " + " | ".join(["---"] * len(cleaned[0])) + " |" rows = ["| " + " | ".join(row) + " |" for row in cleaned[1:]] return "\n".join([header, separator] + rows)

把表格转成 Markdown——LLM 对 Markdown 表格的理解能力远强于纯文本拼接。

扫描件 PDF

如果 PDF 是扫描件,get_text()会返回空,需要走 OCR 分支(PyMuPDF 渲染成图片 → pytesseract 识别)。实际项目中先尝试get_text(),空了再走 OCR。


Word 解析

.docx底层是 XML,结构比 PDF 清晰,python-docx很好用。

pip install python-docx ``````plaintext from docx import Documentdef parse_docx(filepath: str) -> ParsedDocument: doc = Document(filepath) paragraphs = [] for para in doc.paragraphs: text = para.text.strip() if not text: continue # 标题样式转 Markdown,保留文档结构 if para.style.name.startswith("Heading"): level = para.style.name.replace("Heading ", "") text = f"{'#' * int(level)} {text}" paragraphs.append(text) # 表格也提取 for table in doc.tables: rows = [[cell.text.strip() for cell in row.cells] for row in table.rows] paragraphs.append(table_to_markdown(rows)) content = "\n\n".join(paragraphs) return ParsedDocument(filename=..., content=content, file_type="docx", ...)

要点:Word 的Heading 1/Heading 2转成#/##,保留文档结构,对 LLM 理解非常有帮助。


Excel 解析

Excel 的特殊性:本身就是结构化数据,需要把表格数据转成 LLM 能理解的文本格式

pip install openpyxl ``````plaintext from openpyxl import load_workbookdef parse_xlsx(filepath: str) -> ParsedDocument: wb = load_workbook(filepath, read_only=True, data_only=True) pages = [] for sheet_name in wb.sheetnames: ws = wb[sheet_name] rows = [] for row in ws.iter_rows(values_only=True): if all(cell is None for cell in row): continue rows.append([str(cell) if cell is not None else "" for cell in row]) if rows: md = table_to_markdown(rows) pages.append(f"## Sheet: {sheet_name}\n\n{md}") wb.close() return ParsedDocument(...)

注意

  • read_only=True:大文件必须开,否则内存炸。
  • data_only=True:读公式计算后的值,不然得到=SUM(A1:A10)
  • 合并单元格需要特殊处理(左上角值填充被合并的空格)。

HTML 解析

难点在于去噪——网页里真正有价值的"正文"可能只占 HTML 的 20%。

推荐readability-lxml(Firefox 阅读模式的算法),能自动识别正文区域:

from readability import Document as ReadabilityDocumentfrom bs4 import BeautifulSoupdef parse_html_readability(filepath: str) -> ParsedDocument: with open(filepath, encoding="utf-8") as f: html = f.read() doc = ReadabilityDocument(html) soup = BeautifulSoup(doc.summary(), "lxml") content = "\n".join( line for line in soup.get_text(separator="\n", strip=True).split("\n") if line.strip() ) return ParsedDocument(...)

在线网页只需加个httpx.get(url)获取 html,其余逻辑一致。


统一入口:FileParser 类

class FileParser: SUPPORTED_TYPES = {".pdf": "pdf", ".docx": "docx", ".xlsx": "xlsx", ".html": "html"} def parse(self, filepath: str) -> ParsedDocument: ext = os.path.splitext(filepath)[1].lower() file_type = self.SUPPORTED_TYPES.get(ext) if not file_type: raise ValueError(f"不支持的文件格式: {ext}") parser_map = {"pdf": parse_pdf, "docx": parse_docx, "xlsx": parse_xlsx, "html": parse_html_readability} return self._post_process(parser_map[file_type](filepath)) def _post_process(self, doc: ParsedDocument) -> ParsedDocument: # 清理多余空白、标准化换行 content = re.sub(r"\n{3,}", "\n\n", doc.content).strip() doc.content = content return doc def parse_batch(self, filepaths: list[str]) -> list[ParsedDocument]: results = [] for fp in filepaths: try: results.append(self.parse(fp)) except Exception as e: print(f"解析失败 [{fp}]: {e}") return results

使用:

parser = FileParser()doc = parser.parse("./docs/技术方案.pdf")print(f"字数: {doc.total_chars}, 页数: {doc.page_count}")

生产环境注意事项

  1. 文件大小限制:大文件会吃内存,设 50MB 上限。
  2. 超时控制:某些 PDF 解析可能卡住(大扫描件做 OCR),用asyncio.wait_for加 60 秒超时。
  3. 编码检测:HTML 文件编码不一定是 UTF-8,用chardet检测。
  4. 安全检查:限制文件扩展名白名单,使用tempfile并及时清理。

总结

  1. 文件解析是 RAG 第一关——解析质量决定检索和回答的上限。
  2. 每种格式都有专门的坑:PDF 最难,HTML 重在去噪。
  3. 统一输出格式ParsedDocument)是关键设计——后续切片、入库、检索都基于这个结构。
  4. 工具选择:PDF 用 PyMuPDF + pdfplumber,Word 用 python-docx,Excel 用 openpyxl,HTML 用 readability-lxml。
  5. 表格转 Markdown:LLM 对 Markdown 表格的理解能力远强于纯文本拼接。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

http://www.cnnetsun.cn/news/2679486.html

相关文章:

  • 告别‘调包侠’:在EduCoder上用纯NumPy实现CNN前向传播的避坑指南
  • Multi-Agent商业模式:平台化生态构建与开发者激励策略
  • 运维测试人员转网安必看:转行方向 + 方法 + 避坑指南
  • 【Ragent】企业级 Agentic RAG 智能体:让 AI 落地从“调 API“变成“真工程“
  • 用Arduino Nano与8x8 LED矩阵复刻《太空侵略者》街机游戏
  • SURF 图像特征提取算法新手实战指南
  • Gemini剧本写作辅助:7天从零构建专业级分场大纲,附赠2024好莱坞最新结构模板
  • 人工智能从内容生成到自主进化
  • 联想刃7000K BIOS隐藏选项终极解锁指南:3分钟释放完整硬件潜能
  • WeChatMsg:你的数字记忆终极保存方案深度解析
  • 今天不配置Gemini社媒工作流,明天你的KOC合作成本将上涨210%
  • Windows运维小技巧:用ForceDelete命令行模式批量清理被锁定的临时文件与日志
  • Gemini用户激活率提升42%的实战路径(2024最新A/B测试数据验证)
  • 网站规范揭秘:涵盖 10 领域 128 主题,开源构建助力打造优质网站
  • Gemini多模态推理延迟突增事件复盘(官方未公开的172ms性能拐点溯源)
  • 【算法分析与设计】第26篇:参数化算法与固定参数可解性理论
  • 【算法分析与设计】第27篇:近似算法设计:贪心近似与局部搜索
  • AI应用增长瓶颈突破,深度拆解Top 10 Gemini截图文案的CTA埋点逻辑与用户行为热图映射
  • 抖音音乐下载终极指南:免费开源工具实现批量处理与高效管理
  • 书匠策AI:课程论文的“外挂“已上线,再也不用对着空白文档发呆了
  • 【紧急预警】Gemini 2.5.2补丁已悄然上线!3个高危breaking change正在影响金融/医疗类LLM流水线
  • VMware macOS解锁神器:3步开启苹果系统虚拟化之旅
  • 做国内还是出海
  • MH迈汇:从品牌建设看平台长期价值
  • 深度学习生成模型(三)—— 扩散模型:DDPM 与 Stable Diffusion(五十一)
  • 高效文献去重实战指南:ZoteroDuplicatesMerger智能合并插件完整解决方案
  • Windows 11终极清理指南:用Win11Debloat一键释放系统潜能
  • 基于Arduino与WS2812B的智能LED光管制作全解析
  • 百度网盘秒传脚本:5分钟快速上手,告别文件分享失效烦恼
  • ViVeTool GUI深度解析:Windows隐藏特性管理的技术实战指南