ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PPT课件非结构化数据解析:用python-pptx与LibreOffice批量提取文本表格

PPT课件非结构化数据解析:用python-pptx与LibreOffice批量提取文本表格 简介《发展经济学》马工程课件第十章区域经济发展面向经济学专业师生及备考者系统讲解区域经济发展三大经典理论。课件先介绍米尔达尔的地理二元经济发展理论以循环累积因果原理解释回波效应与扩散效应说明政府干预在缩小地区差距中的作用随后阐述佩鲁的增长极理论强调通过增长极带动周边经济并指出其局限最后梳理源自产品生命周期的梯度转移理论说明产业与技术如何依梯度有序扩散。这些理论对理解中国西部大开发、中部崛起等区域战略具有直接参考价值。资源为单个PPT文件共1个文件压缩包约10.46MB适合课堂教学、自学复习或考前梳理。已有381人学习使用内容结构完整节选包含章节框架、理论讲解与评价总结可直接用于课件制作或辅助学习。1. 课件不叫课件叫非结构化数据以《发展经济学》区域经济发展章节为例把《发展经济学》马工程课件 10.第十章 区域经济发展.ppt 这样的文件拖进搜索引擎你会得到两条结果要么是下载链接的重复拷贝要么是课件站的广告页。它真正的内容——那一百多页胶片里的文字、数据表、箭头图——几乎没有被索引。原因是这类课件本质上是一个非结构化数据容器文件名里的“第十章”是唯一可搜索的元数据。做技术的人遇到这类文件第一反应不该是“打开看看”而是“怎么把它变成能查、能算、能重排的数据”。这篇博文就围绕这个具体文件展开先拆解 .ppt 与 .pptx 的格式差异再写代码提取文本和表格接着处理批量课件的命名与索引最后把结果写回新 PPT 的备注区。适合需要用程序批量处理教学课件、会议材料或行业报告并且想绕开手动复制粘贴的工程师。2. 先拆文件格式.ppt 与 .pptx 的处理边界和转换命令2.1 为什么不能直接对 .ppt 用 python-pptxpython-pptx 是一个面向现代 PowerPoint 格式的库它的底层直接操作的是 Open XML 包。老式 .ppt 则是 OLE 复合文档内部包含大量二进制流比如文本流、图片流和格式记录。这两种格式在文件入口上就不一样。我们如果把 .ppt 文件直接传给Presentation()构造函数python-pptx 会在解压环节抛异常因为它期望的是一个 ZIP 容器。我最早遇到这个问题时以为是文件路径不对反复检查才发现是扩展名把方向带偏了。所以在写任何解析逻辑之前先做一个简单的后缀判断把格式分清楚。下面这段脚本用pathlib拿到后缀并归类from pathlib import Path def check_suffix(path: str) - str: suffix Path(path).suffix.lower() if suffix .pptx: return pptx if suffix .ppt: return ppt raise ValueError(f不支持的格式: {suffix}) print(check_suffix(《发展经济学》马工程课件 10.第十章 区域经济发展.ppt))函数的返回值是字符串ppt或pptx后面可以拿它做分支处理。注意这里用了lower()因为实际用户上传的文件后缀常常是大写.PPT。Path(path)对中文、空格文件名都没有问题但在 shell 命令里直接拼接时必须加引号。2.2 用 LibreOffice 把 .ppt 批量转成 .pptx 的命令老式 .ppt 的转换最常见的做法不是自己写二进制解析而是交给 LibreOffice 的无头模式。LibreOffice 内部维护了一个完整的 PowerPoint 导入过滤器转换成功率高而且支持命令行调用。在 Ubuntu 或 CentOS 上安装后执行下面的命令soffice --headless --convert-to pptx \ --outdir ./converted \ 《发展经济学》马工程课件 10.第十章 区域经济发展.ppt--headless表示不弹出 GUI 窗口--convert-to pptx指定输出格式--outdir是输出目录需要提前建好文件名要双引号包住因为里面有空格和中文。这个命令不会修改原文件只在converted目录下生成同名但后缀为 .pptx 的新文件。批量处理时可以用find配合循环。这里有一个经常踩的坑LibreOffice 默认不覆盖已存在的目标文件如果输出目录里已经有同名文件它会自动改名加上序号导致后续脚本找不到预期路径。所以批量转换前最好清空输出目录。转换后的 .pptx 文件结构上已经变成 ZIP 包python-pptx 可以直接读。下表对比了两种格式在关键特征上的差异对比项.ppt.pptx存储结构OLE 二进制复合文档ZIP 压缩的 XML 包直接读取需要解析二进制流解压后读 XMLpython-pptx 支持不支持支持文本检索难以全文索引可以按 XML 节点检索转换工具LibreOffice / WPS无需转换这个表也解释了为什么很多企业知识库项目在处理历史课件时第一步都是把 .ppt 批量升级成 .pptx后续的文本抽取、版本对比、内容审计都要简单得多。2.3 最小读取代码从幻灯片中抽取正文与备注转换完成后就可以用 python-pptx 抽正文。下面这段生成器代码按幻灯片顺序返回每页的文本内容和备注内容from pptx import Presentation def extract_slides(path: str): prs Presentation(path) for idx, slide in enumerate(prs.slides, start1): texts [] for shape in slide.shapes: if shape.has_text_frame: for para in shape.text_frame.paragraphs: line .join(run.text for run in para.runs) if line.strip(): texts.append(line) note if slide.has_notes_slide: note slide.notes_slide.notes_text_frame.text yield { slide_no: idx, content: \n.join(texts), note: note }关键在para.runs一个段落可能由多个 run 组成每个 run 有独立的字体属性直接读para.text也能拿到完整内容但用run.text拼接可以保留原始分段。line.strip()过滤掉纯空白段落。备注部分用has_notes_slide判断避免每张幻灯片都访问不存在的备注页。调用时这样写for data in extract_slides(converted/区域经济发展.pptx): print(data[slide_no], len(data[content]))这里的业务价值在于你不需要打开 PowerPoint就能知道哪几页文字最多、哪几页有备注。对《发展经济学》这种每章几十页的课件这个函数可以成为后续所有统计功能的基础。3. 从“区域经济发展”课件中提取结构化知识3.1 表格数据是重点用 python-pptx 抽取表格并转 DataFrame区域经济发展这一章课件里通常有地区 GDP 对比表、三次产业比重表、人均收入差异表。这些数据不是纯文本而是表格形状。前面extract_slides里的has_text_frame只能处理文本框对表格是读不出来的。正确的做法是判断shape.has_table然后逐行逐格取数再用 pandas 转成 DataFrameimport pandas as pd from pptx import Presentation def extract_tables(path: str): prs Presentation(path) for slide_idx, slide in enumerate(prs.slides, start1): for shape in slide.shapes: if shape.has_table: tbl shape.table rows [] for row in tbl.rows: cells [cell.text.strip() for cell in row.cells] rows.append(cells) if len(rows) 2: df pd.DataFrame(rows[1:], columnsrows[0]) yield slide_idx, dfrow.cells返回该行所有单元格对象.text直接拿文本.strip()去掉首尾空格。把第一行当作列名其余行作为数据体。如果表格有合并单元格合并区域里的文本会在多个位置重复出现后处理时要根据内容去重。一个简单策略是当某行的所有单元格都等于上一行对应单元格时判断为合并扩展行直接丢弃。注意shape.table是 python-pptx 中表示表格对象的属性不是方法后面要跟.rows和.cells不是table.cell()。这在代码里很容易写错。3.2 关键词定位按“增长极”“产业结构”等主题词过滤文本课件文本提取出来后需要快速定位哪些页讲了核心概念。以区域经济学的常见主题词为例可以准备一个关键词列表然后在提取结果里扫描KEYWORDS [增长极, 梯度转移, 产业结构, 集聚效应] def scan_keywords(slides_data, keywordsKEYWORDS): result [] for item in slides_data: hit [kw for kw in keywords if kw in item[content]] if hit: result.append({ slide_no: item[slide_no], keywords: hit, excerpt: item[content][:50] }) return result这个函数返回一个列表每个元素包含页码、命中的关键词、以及前 50 个字符的摘要。excerpt用切片生成注意中文环境下item[content][:50]取的是 50 个字符不是 50 个字节所以不会切坏中文。如果关键词数量大可以先把content统一转成小写再匹配避免大小写干扰。这里有个容易被忽略的点关键词列表本身是领域知识。你可以从标题“区域经济发展”出发结合发展经济学教材目录整理出 20 到 50 个词做成一个外部keywords.txt文件而不是硬编码在脚本里。这样换一个章节只需要换词表。3.3 将结果输出为 JSON保留章节编号与层级抽取的结果最好落盘保存方便下一步处理。JSON 是最通用的格式既能保存文本也能保存结构化字段。下面这段代码把 3.2 的扫描结果和文本内容合并写入import json def save_to_json(data, outputregion_course.json): with open(output, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2)ensure_asciiFalse最关键。如果保留默认的Truejson.dump 会把中文转成\u589e\u957f这样的转义序列虽然不影响程序读取但人眼没法排错。indent2让每层嵌套缩进两个空格体积会大一些但对调试友好。如果你要把这个 JSON 导入 Elasticsearch 或别的检索引擎建议把indent去掉减少一半存储空间。层级问题在这里值得单独说。PPT 不像 Word 那样有明确的标题样式所谓“第十章”的层级往往只能通过字体大小或缩进判断。python-pptx 可以读取run.font.size但课件作者经常直接在母版里设置格式导致单个 run 的字体大小为None。我一般不建议自动判断标题层级而是把slide_no当作索引把内容交给下游人工映射。课件里的章节编号是写死在图里的提取阶段不追求完美分层先把内容完整捞出来。4. 批量处理多个课件命名清洗、内容索引与词频统计4.1 文件名里的“10.第十章”怎么清洗成可用编号真实课件目录里文件命名风格千奇百怪。例如原始文件名是“《发展经济学》马工程课件 10.第十章 区域经济发展.ppt”提取章节号的正则写法如下import re def extract_chapter_no(filename: str) - str: match re.search(r(\d)\.\s*第?[一二三四五六七八九十0-9]章, filename) if match: return match.group(1) return None对于这个具体文件名re.search会匹配到10.第十章并捕获前面的数字10。第?表示“第”字出现了零次或一次这样兼容“10.第十章”和“10.10章”两种写法。[一二三四五六七八九十0-9]章负责匹配中文数字或阿拉伯数字的章节名。返回的字符串10可以直接转成int用于排序。清洗编号的目的是避免字符串排序出现“1, 10, 11, 2”的错乱。如果文件来自多本教材的混排目录建议在提取编号的同时保留原始文件名用字典存储两者映射。4.2 用 pandas 建立课件内容索引表批量处理时我习惯先把所有课件的路径、章节号、幻灯片数量、文本长度汇总成一张表。这样一眼就能看出哪一章内容偏薄哪一章可能含大量贴图import pandas as pd from pathlib import Path def build_index(directory: str): records [] for f in Path(directory).glob(*.pptx): prs Presentation(str(f)) total_text for slide in prs.slides: for shape in slide.shapes: if shape.has_text_frame: total_text shape.text_frame.text if shape.has_table: total_text .join( cell.text for row in shape.table.rows for cell in row.cells ) records.append({ file: f.name, chapter_no: extract_chapter_no(f.name), slides: len(prs.slides), chars: len(total_text) }) return pd.DataFrame(records)Path(directory).glob(*.pptx)只匹配当前目录不递归子目录。需要递归时把glob改成rglob但要注意rglob(*.pptx)会返回完整路径存入表格时要先取.name或相对路径。这里的chars是纯文本字符数把表格里的文本也拼了进来所以能反映课件下含表格的数据量。如果你只想统计正文可以只累加has_text_frame的部分。索引表生成后可以直接用 pandas 的sort_values(slide_no)排序。注意slide_no这列在extract_chapter_no返回None时要先填充为-1否则排序会报错。4.3 用 jieba 分词快速发现章节核心概念文本提取完成后做一次词频统计能快速验证内容完整性。对《发展经济学》区域经济发展这一章分词后出现的高频词如果集中在“增长”“产业”“区域”“发展”说明提取链路工作正常。如果高频词全是“的”“了”“是”说明清洗步骤漏了停用词过滤。以下脚本用 jieba 做词频统计import jieba from collections import Counter def top_keywords(text: str, topn10): words jieba.lcut(text) filtered [ w for w in words if len(w) 1 and w not in STOPWORDS and not w.isdigit() ] return Counter(filtered).most_common(topn)len(w) 1过滤单字词not w.isdigit()去掉单独出现的数字。STOPWORDS可以用现成的中文停用词表。注意 jieba 的lcut返回列表不指定cut_allTrue时默认精确模式对“区域经济发展”这样的词会切分出“区域”“经济”“发展”如果你希望把它当作一个整体可以调用jieba.add_word(区域经济发展)。这一步不是必须的但能显著改善词频结果的可读性。把词频结果存进 JSON 后会发现“增长极”“产业结构”这样的关键词出现在不同页码这就是 3.2 节扫描结果的进阶版由词频驱动而不是由预设关键词驱动。5. 把提取结果写回新 PPT在备注中生成复习笔记5.1 用 python-pptx 创建带备注的幻灯片内容提取和清洗完成后一个很常见的需求是生成“带复习笔记”的新版课件。思路是把每张幻灯片的提取文本、关键词、页码索引写进备注区。下面代码创建一个带备注的空白幻灯片from pptx import Presentation def create_summary_slide(prs, title, notes): slide_layout prs.slide_layouts[1] slide prs.slides.add_slide(slide_layout) slide.shapes.title.text title slide.notes_slide.notes_text_frame.text notes return slideslide_layouts[1]是模板中的“标题和内容”版式不同模板这个索引可能指向不同布局所以最好先打印模板的布局列表确认。notes_text_frame.text可以直接赋值字符串如果备注内容很长python-pptx 不会自动分页但会在单页内滚动展示。用这个函数可以把 3.3 节的 JSON 数据回写成一个可阅读的教学辅助 PPT。5.2 验证方法用正则检查提取是否完整回写之前需要验证提取结果没有漏掉关键内容。我一般用正则匹配来检查原始文本中必须出现的段落是否还在import re def verify(text: str, pattern: str) - bool: return re.search(pattern, text) is not None print(verify(slide.notes_slide.notes_text_frame.text, 区域经济发展))如果返回 False说明这一页的文本可能在分组形状里。python-pptx 的slide.shapes默认不展开分组图形你需要递归遍历shape.shapes。遇到shape.shape_type MSO_SHAPE_TYPE.GROUP时继续向下找。这个坑在高版本 PPT 里非常常见因为作者习惯把标题和装饰线打包成组。5.3 一个可复用的脚本框架含参数说明把前面所有步骤串起来做成一个命令行工具方便对不同课件反复执行import argparse def main(): parser argparse.ArgumentParser(description课件文本提取与回写) parser.add_argument(input, help输入的 pptx 文件路径) parser.add_argument(--output, defaultoutput.pptx, help输出新 pptx 路径) parser.add_argument(--keywords, nargs*, help关键词列表) args parser.parse_args() prs Presentation(args.input) notes extract_slides(args.input) for item in notes: create_summary_slide(prs, fslide {item[slide_no]}, item[content]) prs.save(args.output) if __name__ __main__: main()--keywords使用nargs*后命令行可以写--keywords 增长极 产业结构这样关键词参数不是定长灵活度更高。output默认是output.pptx不会覆盖原文件。如果你要对整个目录做批处理可以在这个框架基础上加一个--directory参数循环调用build_index和extract_tables。注意 Windows 下中文路径要转成Path(str)避免编码问题。本文还有配套的精品资源点击获取
返回列表