简介一份围绕传统药膳养生文化的演示文稿适合中医养生爱好者、健康管理从业者及文化宣讲者用于自学或课件素材。内容从中医养生理念切入明确“治未病”与健康标准系统梳理药膳养生文化自周代“食医”以来的发展脉络从《汉书》“民以食为天”到《黄帝内经》《神农本草经》《伤寒杂病论》等典籍均有涉猎并指出药膳并非食物与药物的简单叠加而是基于中医理论的精准配伍。同时涵盖中药、针灸、按摩、刮痧、食疗、药酒、拔罐、足道、耳疗等中医养生方法重点讲解“因人、因地、因时制宜”的配伍原则并结合冬季温补、夏季清解等实例说明具体应用。全包仅一个文件为PPT格式压缩包约1.55MB结构紧凑便于直接阅读和课堂演示。目前已有99人学习可作为快速了解中华传统药膳养生文化的精炼入门材料。1. 传统药膳养生文化.ppt 不是课件是一堆等着建模的半结构化数据很多团队拿到《传统药膳养生文化.ppt》时第一反应是“把里面的方子摘出来做成Excel”。这个思路没错但做一半会发现根本收不了场同一道药膳在不同版式里出现有的页是“食材-药材-做法”三段式有的页直接贴了一大段养生语录还有的页把功效写进表格里。文字是人能看懂的程序却分不清哪行是主料、哪行是禁忌。这份PPT真正的问题不在于内容多少而在于它的组织方式是按“展示”设计的不是按“查询”设计的。你要把它变成可检索、可更新、可批量出页面的内容资产第一件该做的事不是写爬虫、不是开OCR而是先把数据模型定下来。如果字段不先定义好后面每多解析一页就会多一种例外情况。这篇文章讲的是我自己处理这类文化科普类PPT时的完整路径从字段设计开始用Python把pptx拆成结构化数据做同义词对齐和校验最后落地成一个能查、能看、能继续喂新材料的静态知识库。适合做中医药信息化、内容库建设、知识管理平台的工程师也适合手里攒了一堆行业素材、想把它变成可维护系统的技术人员。全程不需要OCR不需要深度学习一台普通电脑、一份pptx文件就够了。2. 先定数据模型把药膳条目拆成字段而不是拆成页面2.1 PPT 里的药膳信息为什么没法直接当数据库用PPT 的排版逻辑是“让人在一页内看完”所以它会把标题放大、把重点加粗、把步骤用编号列出。这种结构对读者友好但对程序非常不友好。截取一段文字时python-pptx 读到的 text_frame 里包含的是一堆带层级的段落而不是“字段名值”的干净组合。常见做法是先不碰代码拿一份 PPT 从头到尾翻一遍把重复出现的“信息块”列出来。比如“原料”“配料”“药材”“做法”“功效”“宜忌”“出处”“季节”“体质”。这些块不一定每一页都全但多数页会包含其中五六种。把这些块定成字段后PPT 里的每一页就不再是一个版面而是一条“半成品记录”——文本还是散落的但字段边界已经划出来了。还有一个容易被忽略的问题同一份 PPT 里字段名可能是变化的。这一页写“材料”下一页写“食材”再下一页写“原料组成”。这就是数据建模阶段要处理的“同义词”问题而不是解析阶段才想的。建模阶段把这些候选名都记下来后面清洗时统一映射。2.2 一份能覆盖九成药膳页面的字段清单下面这个字段表是在处理过几份中药、养生类素材后整理出来的。它的设计原则是“扁平的记录 少量独立关联表”不用嵌套结构因为从 PPT 提取出来的信息本身就带着不确定性字段越嵌套解析失败的概率越高。字段名类型必填说明idstring是唯一编号建议用拼音或数字不要用中文namestring是药膳名称如“红枣山药粥”categorystring否分类汤/粥/茶/菜/点心materialslist是主要食材每一项是“名称herbslist否药材成分区别于普通食材efficacylist否功效关键词如“健脾”“安神”constitutionlist否适宜体质如“气虚质”“平和质”seasonslist否适宜季节如“春”“秋”methodtext否烹饪步骤原样保留文本tabootext否禁忌或不适宜人群sourcestring否出处如“本草纲目”pageint是在原 PPT 中的页码方便溯源食材和药材为什么要分开两个字段因为在传统药膳里食材红枣、山药和药材当归、黄芪的用量逻辑不一样后续如果要按单位重量计算投放比例分开更合理。areas 字段不要现在做成多对多的关联表PPT 里的信息密度没那么高YAML 里直接塞 list 就能满足需求。2.3 用 YAML 做“原料层”让每一页都能被程序读懂把字段定下来后不要急着写解析脚本先用 YAML 做一个“目标格式”样例。这个样例相当于是整个 pipeline 的契约后面所有解析、清洗、校验都是为了让文本能变成这个结构。id: hongzao_shanyao_zhou name: 红枣山药粥 category: 粥 materials: - 红枣|10枚 - 山药|100g - 大米|50g herbs: [] efficacy: - 健脾 - 益气 constitution: - 气虚质 - 平和质 seasons: - 春 - 秋 method: 大米淘洗后与山药段、红枣同煮大火烧开转小火熬40分钟。 taboo: 湿热质慎用糖尿病患者减少红枣用量。 source: page: 23这个结构有几个好处第一程序读取 YAML 不需要额外解析库之外的逻辑PyYAML 直接能 load 成 dict第二人也能直接看懂中间核对数据时不用开数据库客户端第三缺失字段直接不写不会产生 null 的歧义。命名字段的时候我用“materials”而不是“foods”就是为了把普通食材和药材分开。这个 YAML 样例要先发给业务方确认一遍特别是 efficacy 和 constitution 这两个字段的取值必须约定成有限的几个词否则后面清洗会失控。3. 用 python-pptx 把 .pptx 拆成结构化数据3.1 最小脚本遍历每一页把文字和表格按顺序导出python-pptx 是处理 .pptx 格式事实上的标准库。它不依赖 Office 软件支持读取幻灯片中的 text_frame、表格、图片关系等对象。第一步先做“把文字全量导出来”的脚本这一步的目的不是生成最终数据而是让人能看到每页实际有什么内容方便确认字段映射规则。from pptx import Presentation import sys def dump_pptx(path): prs Presentation(path) for idx, slide in enumerate(prs.slides, start1): print(f\n Slide {idx} ) for shape in slide.shapes: # 表格对象单独处理 if shape.has_table: tbl shape.table for row in tbl.rows: cells [cell.text.strip() for cell in row.cells] print( | .join(cells)) # 文本框对象 elif shape.has_text_frame: for para in shape.text_frame.paragraphs: text .join(run.text for run in para.runs).strip() if text: print(text) if __name__ __main__: dump_pptx(sys.argv[1])执行方式python dump_pptx.py 传统药膳养生文化.pptx dump.txt这段代码里slide.shapes返回当前页所有形状对象has_table和has_text_frame是 shape 的两个关键判断属性分别对应表格和文本框。cell.text是单元格内全部文本para.runs是段落里的富文本片段这里把它们拼接起来是为了去掉格式差异。输出加一个页码分隔符方便后面按页回溯。3.2 把 shape 分成三类标题、正文块、表格不同的 shape 类型处理策略不一样。标题通常在slide.shapes.title里正文块是没有 title 标记的普通文本框表格则要按行读取。分清楚这三类是为了避免后面字段映射时把标题误当成正文。from pptx.util import Inches def extract_shapes(slide): parts [] # 1. 幻灯片标题 if slide.shapes.title is not None: title slide.shapes.title.text.strip() parts.append((title, title)) # 2. 表格优先处理避免文字顺序被拆分 for shape in slide.shapes: if shape.has_table: rows [] for row in shape.table.rows: rows.append([cell.text.strip() for cell in row.cells]) parts.append((table, rows)) elif shape.has_text_frame and not shape slide.shapes.title: body [] for para in shape.text_frame.paragraphs: line .join(run.text for run in para.runs).strip() if line: body.append(line) if body: parts.append((text, \n.join(body))) return parts这里的一个关键点shape slide.shapes.title时要跳过否则标题会被输出两次。shape.has_chart也要注意图表对象在 .pptx 里不是表格直接读不到文本好在这类文化科普 PPT 里极少出现图表。表格单独处理而不是拼进 text是因为表格本身已经带有行列语义转成 CSV 后可以直接归入“材料明细”之类的字段。3.3 用正则把文本按“标签-内容”拆分成字段当文本按照“原料红枣10枚”这种形式出现时直接用正则匹配标签字即可。这种格式在药膳 PPT 里最常见冒号前是字段名冒号后是内容。正则匹配要比遍历查找快得多也更直观。import re FIELD_PATTERN re.compile( r^\s*(原料|材料|食材|配料|药材|做法|功效|宜忌|禁忌|适宜|出处|备注)\s*[:]?\s*(.)$ ) def parse_labeled_text(text): 把 功效健脾益气 之类的行解析成字段名和值。 result {} for line in text.splitlines(): m FIELD_PATTERN.match(line.strip()) if m: result[m.group(1)] m.group(2).strip() return result这个正则的关键在于字符组(原料|材料|食材|…)把可能出现的中文标签全部列出来[:]?同时兼容半角和全角冒号。匹配成功的行group(1)是标签group(2)是值。注意这里没有对“值”再做二次拆分比如“红枣10枚”还需要拆成名称和用量这一步留给清洗阶段用同样的正则按“|”或空格处理不要在解析阶段做太精细的划分否则规则一多就难维护。4. 从文本到记录清洗对齐和校验4.1 约定“一页一膳”的拆分规则解析脚本输出的是一大段文本要变成一条条 YAML 记录第一步是确定“一条记录从哪里开始到哪里结束”。最简单可靠的规则就是“一页一膳”一页算一条记录不管这一页内容多还是少先按页切开。跨页的情况怎么办我在处理时发现一个条目偶尔会占两页第二页只有后半段做法和禁忌。这种情况靠脚本自动判断不可靠我一般会在生成 YAML 后人工核对分页把断开的第二条合并掉。先按页拆分是因为页边界在 PPT 里是明确存在的不会歧义跨页合并是少数异常用人工处理成本最低。4.2 建立一个指向规范名的同义词表同义词问题是清洗里最实际的一个环节。同一份 PPT 里“红枣”“大枣”“干枣”可能都指同一个东西“乌鸡”“竹丝鸡”也是同一食材。如果不清洗后面做“按食材搜索”时搜“红枣”永远查不到“大枣”开头的条目。SYNONYMS { 大枣: 红枣, 干枣: 红枣, 竹丝鸡: 乌鸡, 元肉: 龙眼肉, 桂圆: 龙眼肉, 淮山: 山药, } def normalize_material(name): 把同义词统一为规范名。 name name.strip() return SYNONYMS.get(name, name)这里选择用字典做简单映射不用分词模型。原因很简单药膳里的食材名相对封闭几百个词足够覆盖字典可维护、可解释业务方要加词直接改配置。规范名的选择标准不是“正确”而是“最常用”。如果业务方规定以“本草纲目”为准那“淮山”映射到“山药”“山药”就不用往任何方向映射。注意不要做双向映射否则“红枣”和“大枣”会互相覆盖最终结果取决于字典遍历顺序极难排查。4.3 校验脚本建库之前先发现脏数据解析完成后生成的一堆 YAML 文件不能直接发布。校验脚本是 data pipeline 里最被低估的一环。它要能检查出三种问题字段缺失、字段值非法、页面引用出错。import glob import yaml REQUIRED_FIELDS [id, name, page] VALID_CONSTITUTIONS {平和质, 气虚质, 阳虚质, 阴虚质, 痰湿质, 湿热质, 血瘀质, 气郁质, 特禀质} def validate(filepath): with open(filepath, encodingutf-8) as f: data yaml.safe_load(f) errors [] for field in REQUIRED_FIELDS: if field not in data or data[field] in (None, ): errors.append(f缺少必填字段: {field}) if constitution in data: for c in data[constitution]: if c not in VALID_CONSTITUTIONS: errors.append(f未知体质: {c}) if not isinstance(data.get(page, 0), int): errors.append(page 字段必须是整数) if errors: return False, errors return True, [] if __name__ __main__: for yml in glob.glob(entries/*.yaml): ok, errs validate(yml) if not ok: print(yml, errs)yaml.safe_load把文件解析成 dict然后按字段逐一检查。校验规则先定义“必须存在”的字段再检查枚举值是否在约定集合内。这个方法不检查“id 是否重复”因为 YAML 文件名一般就是 id重复会被文件系统挡住。校验脚本的价值在于让错误在进入检索系统之前暴露而不是等上线后用户搜到才发现的“空功能”页面。5. 把结构化数据变成可浏览的药膳手册最后一步集成5.1 用 MkDocs 把 YAML 变成 HTML 页面数据清洗干净后要给它一个“可浏览”的出口。常见做法是用 MkDocs 这类静态站点生成器把每个 YAML 条目渲染成一个 html 页面天然支持全文搜索不需要搭服务直接扔到任意静态托管就能访问。mkdocs new yaoshan cd yaoshan cp ../entries/*.yaml docs/在mkdocs.yml里配置导航和搜索插件site_name: 传统药膳养生文化 theme: name: material plugins: - search nav: - 首页: index.md - 药膳库: entries/生成静态站点的命令mkdocs build这里 doc 文件夹下的 YAML 需要先批量转换成 markdown 文件再加一个简单的 Jinja2 模板做渲染。这是全流程里少有的纯胶水代码但作用很直接之后每新增一份 PPT跑一遍解析脚本再mkdocs build整个站点就更新了。5.2 加标签让检索命中“场景”而不是命中“菜名”药膳检索有个特性用户搜的可能不是菜名而是“最近有点虚”“春天吃什么”。如果只对文档标题做搜索这类需求是搜不到的。我给每个条目加了两个元信息标签适宜节气春季/谷雨/立秋和体质标签。这样用户搜索“健脾”或“气虚”MkDocs 内置的搜索会命中正文里的 efficacy 和 constitution 字段。5.3 内容更新时的二次构建技巧这套流程建立后的日常维护比想象中简单。新拿到的 PPT 文件放到input/文件夹跑一遍python parse.py input/xxx.pptx输出到entries/再执行校验脚本最后mkdocs build。偶尔出现跨页合并和同义词缺失问题改完 YAML 重新构建一遍耗时不到一分钟。要验证构建出的页面数量和条目数量一致可以用grep -c id: entries/*.yaml一行命令核对出现不一致时优先检查是否有空 YAML 文件或者页数重复的情况。整个方案的维护成本集中在“新词条进同义词表”这一件事上其余环节都是自动化完成的。本文还有配套的精品资源点击获取