Python文本挖掘实战:出土经济文献清洗、关键词提取与查询系统

发布时间:2026/10/22 2:39:40
Python文本挖掘实战:出土经济文献清洗、关键词提取与查询系统 如果要把一批与经济相关的出土文献整理成可检索、可统计的数据库最麻烦的往往不是历史考证本身而是资料格式混乱、释文版本不一致、关键词难以统一。手工维护这样的资料库效率很低也容易漏查漏统计。本文围绕甲骨文等出土文献中的经济类记录分享一套基于 Python 的文本清洗、关键词提取和本地查询工具适合历史数字化项目、资料整理脚本和入门 NLP 练习。需要说明的是本文不打算对“古代经济治理”下定论更不会去争议某一种历史叙事是否正确。文章的核心是把分散的释文材料用工程化方式组织成干净、可检索、可统计的数据集。只要资料本身来自公开可靠的渠道这套工具就可以复用到碑刻、简牍、书信档案等各类文献数字化场景中。1. 背景与核心概念1.1 什么是出土文献文本挖掘文本挖掘并不是新的概念它指的是从非结构化文本中提取结构化信息的过程。对于古代文献来说原始材料往往以拓片、照片、扫描图或学者手录释文的形式存在计算机不能直接理解其中的句读和语义。文本挖掘的第一步是把这些材料转成可编辑的文字文本再做清洗、分词、统计和索引。经济类记录在出土文献中非常常见例如田猎、农作物收成、贡纳物品、牲畜数量、手工器物等。研究者在整理这类材料时最关心的通常不是单个字词的长篇考证而是三个问题哪些记录涉及经济主题这些记录在哪些时间段或地点出现不同关键词的频次分布如何这正好是结构化文本检索能够解决的问题。1.2 为什么选择甲骨文作为示例甲骨文是商代晚期以占卜记录为主的出土文字主要发现于河南安阳殷墟一带。其内容常涉及农业、田猎、贡纳、战争、祭祀等对研究当时的经济活动有重要参考价值。由于甲骨文释文存在大量异体字、假借字和残辞数字化整理比普通古籍更难也更需要规范的数据结构。不过要特别注意甲骨文释文具有很强专业性。同一片甲骨在不同著录书中的隶定写法可能不同补字、缺字、通假字的处理方式也不一样。本文的工具逻辑建立在已经由专业学者整理好的释文或现代译文之上不负责自动识别拓片也不参与古文字释义层面的判断。1.3 技术方案的边界本文给出的方案属于“资料整理后半段”假设你已经拿到了可编辑的文本数据需要做清洗、统计和查询。至于拓片如何识别、文字如何隶定、真伪如何判断不属于这套脚本的处理范围。在工程上这个项目会用到 pandas 处理表格数据使用规则清洗文本再用关键词词典统计经济类词汇最后通过 Flask 提供一个简单的本地查询接口。整个项目可以在普通笔记本上运行不依赖服务器和大数据平台。2. 环境准备与版本说明2.1 运行环境本文示例以 Python 3.9 及以上版本为准操作系统可以是 Windows、macOS 或 Linux。下面的命令在 Windows 命令提示符和 Linux/macOS 终端中都可以使用只是个别中文字体路径需要根据系统调整。建议先创建独立的虚拟环境避免依赖冲突。在项目根目录执行python -m venv venvWindows 系统激活虚拟环境venv\Scripts\activateLinux 或 macOS 系统激活虚拟环境source venv/bin/activate2.2 依赖清单项目需要以下第三方库库名用途pandas读取和处理 CSV 数据flask提供本地查询接口wordcloud生成关键词词云matplotlib渲染并保存词云图片jieba对现代译文做分词演示创建一个requirements.txt文件内容如下pandas flask wordcloud matplotlib jieba安装依赖pip install -r requirements.txt版本需要根据你的实际环境调整本文重点演示完整实现思路。2.3 项目目录结构建议按下面的目录组织工程原始数据、处理脚本、词典、输出结果分开存放economic-doc-mining/ ├── data/ │ ├── jiaguwen_records.csv │ └── jiaguwen_records_clean.csv ├── config/ │ ├── econ_terms.txt │ └── stopwords.txt ├── output/ │ ├── keyword_stats.csv │ └── keyword_cloud.png ├── scripts/ │ ├── clean_text.py │ ├── extract_keywords.py │ ├── tokenize_text.py │ └── app.py ├── requirements.txt └── README.md这种结构的好处是数据、代码、配置相互隔离。后续如果新增字典或扩充数据不需要改动脚本主体。3. 核心语法与原理拆解3.1 数据表设计要把零散的文献资料变成可统计的结构化数据第一步是设计表格字段。对于出土文献建议至少包含以下列字段名说明id记录编号保持唯一source来源著录或数据库名称category主题分类如 agriculture、hunting、tributeperiod时期或分期信息original_text原始释文或原文translated_text现代汉语译文或整理说明notes备注、补字说明、审核状态推荐统一使用 CSV 格式存储因为 CSV 轻量、跨平台、容易用 pandas 读取。不过要注意原始释文里可能包含特殊符号例如□表示缺字[]表示补字。这些符号在清洗阶段需要特别处理不能简单删除否则会丢失释文信息。3.2 文本清洗的作用原始数据通常存在换行、多余空格、全角半角混用、特殊符号等问题。如果不做清洗关键词匹配时很容易出现“田”能查到但加了全角空格后“田”查不到的情况。清洗的目标是统一格式但不要破坏文献原意。对于经济类统计推荐清洗策略如下将换行符替换为空格避免跨行文本被硬拆开。多个连续空格压缩为一个空格。删除不需要的 URL、英文字符以外的干扰符号。保留汉字、数字、常用中文标点。对□等缺字符号可以保留或按需替换为占位符不能直接丢弃。3.3 关键词词典设计关键词统计有两种常见做法一种是用 jieba 通用分词后统计高频词另一种是使用自定义经济类术语词典直接匹配。前者的优势是发现未知词后者的优势是结果更可控、解释成本更低。本文推荐“词典匹配为主、分词为辅”的组合策略。先在config/econ_terms.txt中维护一份经济类词表词表需要由熟悉文献的整理者审核。示例词表如下田 禾 麦 黍 年 刈 获 猎 渔 贡 献 牛 羊 马 贝 丝 帛 车 舟 仓 廪 谷 粟 酒 鬯注意这只是一个演示词表不代表甲骨文中这些字全部具有经济含义。实际项目中词表应当经过专题文献综述和专业人员确认。3.4 为什么不能直接把甲骨文原文交给分词器jieba 是基于现代汉语语料训练的分词工具对碑刻、简帛、甲骨文的切分效果并不稳定。甲骨文原文没有现代句读频繁出现一字多义、通假字、缺字直接分词会产生大量无意义片段。更合理的做法是把原始释文与整理后的现代译文分开存放统计操作在translated_text或标注后的文本上执行。这样既能保留原文资料又能让 NLP 工具有一个相对规范的句子边界。下面是一个简单的分词演示脚本用于观察现代译文的分词效果。注意它不对原始释文生效。# 文件路径scripts/tokenize_text.py import jieba import pandas as pd df pd.read_csv(./data/jiaguwen_records_clean.csv, encodingutf-8) for text in df[clean_text].head(5): words [w for w in jieba.lcut(text) if w.strip()] print(words)运行后会输出类似下面的分词结果[商王, 卜问, 今年, 农作物, 是否, 有, 好收成]这里只是一个通俗示例。如果你要做更严谨的学术文本分析建议配合专家整理的专名表一起使用。4. 完整实战案例4.1 准备演示数据为了演示流程先准备一份模拟数据。以下内容仅用于说明数据分析过程不是真实甲骨文释文也不代表任何学术判断。请勿把它用于正式研究引用。文件路径data/jiaguwen_records.csvid,source,category,period,original_text,translated_text,notes a001,演示资料,agriculture,商代晚期,示例原文,商王卜问今年农作物是否有好收成,示例数据 a002,演示资料,hunting,商代晚期,示例原文,田猎并记录捕获猎物的种类和数量,示例数据 a003,演示资料,tribute,商代晚期,示例原文,记录某地进贡的牲畜和物资,示例数据 a004,演示资料,agriculture,商代晚期,示例原文,卜问禾苗生长是否会遇到灾害,示例数据 a005,演示资料,trade,商代晚期,示例原文,记录交换贝和丝的记录,示例数据 a006,演示资料,fishing,商代晚期,示例原文,记录渔获数量较多,示例数据 a007,演示资料,animal_husbandry,商代晚期,示例原文,登记牛栏中的牛数量,示例数据 a008,演示资料,storage,商代晚期,示例原文,检查仓廪中粮食储存情况,示例数据 a009,演示资料,agriculture,商代晚期,示例原文,麦子成熟后准备收割,示例数据 a010,演示资料,hunting,商代晚期,示例原文,猎获鹿若干只并记录用途,示例数据original_text一栏保留原文信息这里示例用“示例原文”代替。translated_text是整理后的对照文本是后续统计的主要对象。4.2 编写文本清洗脚本清洗脚本负责读取原始 CSV清洗译文并生成新文件。文件路径scripts/clean_text.py# -*- coding: utf-8 -*- import re import pandas as pd def clean_text(text): 清洗单个文本字段。 text str(text) if text is not None else text text.replace(\n, ) text re.sub(r\s, , text) # 保留中文字符、数字、常用标点去掉其余噪音字符。 text re.sub(r[^\u4e00-\u9fff0-9A-Za-z。、《》], , text) return text.strip() def main(): df pd.read_csv(./data/jiaguwen_records.csv) if clean_text not in df.columns: df[clean_text] df[clean_text] df[translated_text].fillna().map(clean_text) df.to_csv(./data/jiaguwen_records_clean.csv, indexFalse, encodingutf-8-sig) print(f清洗完成共 {len(df)} 条记录) if __name__ __main__: main()这里的关键是encodingutf-8-sig。它会在文件开头加入 BOM让 Windows 下的 Excel 直接打开 CSV 时不出现中文乱码。如果只在 Linux 终端中使用改成utf-8也可以但为了兼容办公场景建议保留utf-8-sig。清洗后的数据仍然保留original_text不会破坏原始释文信息。clean_text只作为检索和统计字段存在。4.3 编写关键词统计脚本关键词统计脚本会读取config/econ_terms.txt词典在清洗后的文本中匹配词条并输出频率表。文件路径scripts/extract_keywords.py# -*- coding: utf-8 -*- import re from collections import Counter import pandas as pd def load_terms(path): 加载关键词词典。 with open(path, encodingutf-8) as f: terms [line.strip() for line in f if line.strip()] return terms def count_terms_in_text(text, terms): 统计单个文本中的关键词次数。 counter Counter() for term in terms: # 这里使用正则转义避免特殊字符影响匹配。 count len(re.findall(re.escape(term), text)) if count: counter[term] count return counter def main(): df pd.read_csv(./data/jiaguwen_records_clean.csv, encodingutf-8) terms load_terms(./config/econ_terms.txt) total_counter Counter() for text in df[clean_text].fillna(): total_counter count_terms_in_text(text, terms) print(关键词频次 TOP 20) for word, count in total_counter.most_common(20): print(f{word}\t{count}) result pd.DataFrame(total_counter.most_common(), columns[term, count]) result.to_csv(./output/keyword_stats.csv, indexFalse, encodingutf-8-sig) print(结果已保存到 output/keyword_stats.csv) if __name__ __main__: main()这段代码的统计逻辑很简单遍历词典中的词统计它在每一条翻译文本里出现的次数。因为词典中的词大多是单字或短词所以准确率比通用分词高。缺点是如果词表存在包含关系例如同时包含“田”和“田猎”统计数据会重复计算。实际使用时可以把统计结果看成“粗粒度命中情况”而不是严格的语言学词频。4.4 编写本地查询接口为了方便检索某条记录是否包含指定关键词可以再加一个 Flask 查询接口。文件路径scripts/app.py# -*- coding: utf-8 -*- import pandas as pd from flask import Flask, jsonify, request app Flask(__name__) df pd.read_csv(./data/jiaguwen_records_clean.csv, encodingutf-8) app.route(/api/search, methods[GET]) def search(): q request.args.get(q, ) if not q: return jsonify({message: 请输入查询词, data: []}) result df[df[clean_text].str.contains(q, naFalse, regexFalse)] data result.head(20).to_dict(orientrecords) return jsonify({total: len(result), data: data}) app.route(/api/stats, methods[GET]) def stats(): category request.args.get(category, ) if category: sub df[df[category] category] else: sub df return jsonify({category: category, count: len(sub), records: sub.head(10).to_dict(orientrecords)}) if __name__ __main__: # 本机调试时可以开启 debug生产环境务必关闭。 app.run(debugTrue, port5000)启动接口python scripts/app.py浏览器访问http://127.0.0.1:5000/api/search?q农作物返回结果中会包含所有clean_text含“农作物”的记录。再访问http://127.0.0.1:5000/api/stats?categoryagriculture可以看到 agriculture 类别的记录数量和前 10 条明细。这里要提醒一句Flask 自带的服务适合本机测试和内网小范围使用不适合直接暴露到公网。如果要把查询接口开放给更多人应加认证、限流和访问日志并使用 Waitress 或 Gunicorn 等生产级 WSGI 服务器。4.5 生成词云为了快速查看核心关键词分布可以生成一张词云图。文件路径scripts/gen_wordcloud.py# -*- coding: utf-8 -*- import pandas as pd from wordcloud import WordCloud import matplotlib.pyplot as plt def main(): df pd.read_csv(./data/jiaguwen_records_clean.csv, encodingutf-8) text .join(df[clean_text].fillna()) # 中文字体路径需要根据操作系统调整。 # Windows 常见C:/Windows/Fonts/simhei.ttf # macOS 常见/System/Library/Fonts/PingFang.ttc # Linux 常见/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc wc WordCloud( font_pathC:/Windows/Fonts/simhei.ttf, width800, height600, background_colorwhite, ).generate(text) plt.figure(figsize(10, 6)) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.tight_layout() plt.savefig(./output/keyword_cloud.png, dpi200) print(词云已保存到 output/keyword_cloud.png) if __name__ __main__: main()运行python scripts/gen_wordcloud.py如果词云图里的中文显示成方框说明font_path指定的字体文件不存在或该字体不支持中文。换用系统里实际存在的中文字体即可。4.6 运行完整流程建议每次新增数据后按顺序执行python scripts/clean_text.py python scripts/extract_keywords.py python scripts/gen_wordcloud.py如果还要查询接口再执行python scripts/app.py清洗脚本生成干净数据统计脚本生成频次表词云脚本生成可视化结果查询接口支持按关键词和类别检索。整个流程可以重复执行数据更新后不需要改代码。5. 常见问题与排查思路5.1 高频问题排查表问题现象常见原因解决思路Excel 打开 CSV 中文乱码编码用了 utf-8 而不是 utf-8-sig写入 CSV 时使用 encodingutf-8-sig关键词统计结果为空词典路径错误或文本全被清洗删除检查 config/econ_terms.txt 是否存在打印清洗后文本词云中文显示方框系统没有指定中文字体修改 WordCloud 的 font_path 为可用的中文字体查询接口启动失败端口被占用修改 port5000 为其他端口或关闭占用进程查询不到某个词clean_text 为空检查 CSV 中 translated_text 字段是否有值统计词频偏多词典存在互相包含的词条人工审核词表必要时只保留最大粒度词条5.2 清洗后文本为空的处理如果清洗脚本运行后发现clean_text字段全是空值或异常短优先检查原始 CSV 的列名。CSV 表头不能有多余空格例如translated_text和translated_text会被 pandas 视为不同字段。另外如果中文文本被错误识别为NaN在读取后要执行fillna()否则后续str.contains和字符串处理都可能报错或跳过记录。5.3 词表覆盖不足的问题当词典中缺少某个经济类词时统计结果会偏低。不能简单通过增加通用词来提高覆盖率因为通用词可能存在大量非经济含义。比较好的做法是分两层先统计高频词再由研究者从高频词里筛出经济相关词补充进正式词表。这种“先探索、后固化”的做法比一次性拍脑袋列词表更可靠也更符合实际研究的迭代节奏。6. 最佳实践与工程建议6.1 数据来源必须可追溯出土文献数字化最忌讳的是来源不清。每一条记录都应该带有source字段指向公开著录、数据库编号或整理者名称。项目里如果使用扫描件建议单独维护一份文件清单记录文件来源、授权状态和处理人。来源不明或未公开授权的资料不应上传到公共服务器也不应在博客中直接公布完整扫描图。即使在本地研究中使用也要遵守相关机构和数据库的使用协议。6.2 使用多版本释文管理同一片甲骨可能存在多种释文。有的差异很小有的可能影响统计结果。建议增加version字段例如version《合集》释文或version某学者整理本。统计分析时默认只针对某一个版本不要混合多个版本否则同一个字会被重复统计。如果需要做版本比对可以把多个版本放在不同的 CSV 文件或分目录中再写专门的 diff 脚本而不是把所有版本塞进同一张统计表。6.3 区分原文和整理译文原始释文和现代译文是两种不同性质的数据。原始释文是历史材料现代译文是整理者提供的解释。这两者不能混在一个字段里做关键词匹配。统计现代译文出现的“田”不代表原文中一定写的是“田”。因此本文在数据表中单独保留了original_text和translated_text。查询和词频统计默认以translated_text为主如果要检索原始释文应明确区分口径例如搜索字段改为original_text。6.4 安全边界与最小权限这个项目本质上是一个文本检索工具不涉及任何敏感系统操作。不过只要上线了 Web 接口就要考虑权限问题。建议做法是Flask 只监听127.0.0.1不要监听0.0.0.0如果要开放访问应增加登录认证、操作审计和请求限流。不要把数据库连接字符串、API 密钥或未公开文献扫描件放在 CSV 中一起提交。项目中的配置文件、词典、数据文件最好分开管理必要时把敏感资料放入.gitignore。6.5 结果解释要克制文本挖掘工具输出的只是统计数字不是历史结论。某个词频次高可能只是因为保存下来的材料数量多不代表那件事在当时的经济活动中更重要。任何数字在进入结论之前都需要结合文献背景、考古信息和专业人士判断。所以这套工具的定位是“辅助检索与整理”而不是“自动得出历史规律”。它能让研究者快速定位材料但最终解释权仍然属于研究者本人。7. 总结与下一步学习方向本文从资料整理的角度完成了一个经济类出土文献检索小工具。通过 pandas 清洗表格数据通过自定义词典统计关键词频次通过 Flask 提供本地查询接口再通过词云快速展示文本分布。整套代码结构简单可以复用到简牍、碑刻、契约文书等多个文献数字化场景。如果继续扩展这个项目可以先从三个方向入手一是接入 OCR 识别让扫描拓片自动转成文本不过这需要专门的古文字识别模型二是把 CSV 换成 SQLite 或 MySQL让千万级记录也能高效检索三是引入向量检索做语义查询例如输入“农业收成”也能匹配到“禾麦黍稷”相关的记录。实际项目中更优先的是数据质量。先把来源字段、版本字段、审核状态补齐再优化算法也不迟。好的词典和干净的原始数据远比花哨的分析模型更有价值。如果你在配置过程中遇到环境问题可以先用文章开头的虚拟环境隔离依赖遇到统计结果异常先打印清洗后的文本排查再检查词典。把每一步跑通之后再迁移到自己的文献数据上。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询