news 2026/9/9 11:51:32

古诗词JSON数据集:结构设计、清洗实战与工程应用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
古诗词JSON数据集:结构设计、清洗实战与工程应用指南

简介:一份中国诗词大全 JSON 版完整压缩包,源自 GitHub 的 chinese-poetry 开源项目,专供需要本地化处理中文诗词数据的开发者、数据分析师与 NLP 研究者使用,解决 GitHub 直接下载缓慢、clone 容易中断的痛点。压缩包共 1371 个文件,以 1339 个 JSON 数据文件为主体,覆盖唐诗、宋词、元曲、五代词及作者小传等结构化内容,部分文件记录了数万首诗人作品与索引;另含 Markdown 说明文档、SQLite 数据库、辅助 JavaScript 脚本及少量图片,整包约 84.85MB,便于离线检索与批量解析。目前已有 1065 人学习下载,适合需要快速获取高质量诗词语料的中高级 Python 使用者。资源整理自社区开源项目,目录层级清晰、文件命名规范,可直接导入 Elasticsearch、MongoDB 等环境,或用于构建诗词检索问答、文本挖掘与语料训练任务,能显著节省网络访问与数据清洗时间。

1. 为什么我要把《全唐诗》《全宋词》整理成一份JSON

1.1 从一次古诗词App开发经历说起

今年年初我给一个文化类App做内容模块,需求很简单:做一个"每日诗词"卡片,每天推荐一首古诗词,附带作者、朝代、正文。需求听起来不难,但真正动手时才发现——拿不到一份干净、结构化、能直接入库的古诗词数据

网上搜一圈,能找到的基本是这几种:

  • 数据库备份文件(.sql),几十MB起步,结构和字段千奇百怪;
  • Excel/CSV表格,格式混乱,有的把整首诗的标题、作者、正文挤在一个单元格里;
  • 网页爬虫教程,让你自己去抓公开诗词网站,但那些页面本身就存在乱码、重复、缺字问题;
  • 还有一部分是各种"全唐诗大全"的txt文本,一行一首,断句和标点全靠猜。

折腾一周之后我放弃了,决定按自己的标准整理一份"诗词大全JSON版"。

这份数据的目标很明确:拿到手就能用。无论是做App后端、写前端页面、搞NLP训练,还是做个简单搜索工具,都不需要再写一堆恶心的正则去清洗数据。文章末尾我会把这份JSON压缩包的关键结构和踩坑经验完整拆开讲,希望能帮正在做类似内容的同学少走弯路。

1.2 市面上的开源诗词库为什么都不顺手

我不是说网上没有好东西,像一些古籍数字化项目确实做得很好,但它们的定位偏向"学术研究",不太适合直接对接业务开发:

  • 字段太杂,注释、异文、校勘记全堆在一起,一个字段能写一整段话;
  • 按"古籍原书"组织,而不是按"一首诗"组织,想要随机取一首诗还得自己切分;
  • 编码和格式不统一,同一部诗集里简体繁体混用、全角半角混用。

我要做的是面向工程实践的版本:以"单首诗词"为最小单元,统一字段、统一编码、统一格式,再压缩成zip发布。

2. 数据结构设计:一个字段一个坑,我这样建模

2.1 顶层结构:分文件还是合成一个大JSON

这是最早纠结的问题。全唐诗四万多首,全宋词两万多首,加上宋诗、元曲、诗经、楚辞、乐府等,总量在十万首以上

方案有两种:

  1. 全部塞进一个超大JSON文件(比如poetry_all.json);
  2. 按诗集或朝代拆分成多个JSON文件,再用一个索引文件manage。

我最终选了第二种。原因有三点:

  • 单文件超过100MB,很多编辑器和工具打开就直接卡死;
  • 业务端往往只需要某一类数据,比如只做唐诗功能,没必要加载全部;
  • 分文件之后,Git diff、增量更新、按需下载都方便。

压缩包里的顶层目录大致是这样:

poetry-json/ ├── README.md ├── index.json ├── 唐诗/ │ ├── 初唐.json │ ├── 盛唐.json │ ├── 中唐.json │ └── 晚唐.json ├── 宋词.json ├── 宋诗.json ├── 元曲.json ├── 诗经.json ├── 楚辞.json └── 乐府.json

index.json是一份总目录,记录了每个文件对应的诗集名、朝代、收录数量、文件大小,方便程序先加载索引,再按需加载具体文件。

2.2 单首诗词的字段设计与我的取舍

每首诗词我定义为如下结构:

{ "id": "ts-0001", "title": "静夜思", "author": "李白", "dynasty": "唐", "type": "诗", "collection": "唐诗·盛唐", "paragraphs": [ "床前明月光", "疑是地上霜", "举头望明月", "低头思故乡" ], "tags": ["五言绝句", "思乡", "写景"], "notes": "" }

字段设计上有几个有意的取舍,值得说明一下:

正文为什么要存成数组而不是整段字符串?

因为绝大多数使用场景都需要"按行"处理——前端展示要逐行排版,做飞花令要按句子匹配,做鉴赏需要定位到具体某句。如果存成一个string,每次用还得split,而且不同来源的换行符还不一样(\n\r\n都有),存成数组直接从源头规避了这个问题。

为什么要加type字段(诗/词/曲/赋)?

因为"唐诗""宋词"这种按朝代分类其实很粗糙——宋朝人也写诗,唐朝也有词。type字段用来表达文体,collection表达所属合集,两个维度分开,业务端筛选时很灵活。

id命名的规律

id前缀对应来源:ts唐诗、sc宋词、ss宋诗、yq元曲、sj诗经、cf楚辞、yf乐府,后面是四位序号。这样看到id就知道数据归属,而且在合并数据时不会撞id。

2.3 为什么我坚持保留"俗体字"和"异体字"

清洗时最纠结的问题是:要不要做繁体转简体?

我的决定是——保留原汁原味的字形录入,但额外提供简体版本字段,也就是说在paragraphs之外再加了一个可选的paragraphs_simple数组。如果原文是繁体,paragraphs用繁体,paragraphs_simple用简体。如果原文本来就是简体,两个字段保持一致。

原因很简单:做文学研究的人需要看原文,做产品的人需要给普通用户看简体,两个需求都不能得罪。而且古诗词里很多字"简体化"之后反而丢失了平仄和韵脚的信息,比如"雲"和"云"在某些语境下不能混用。这个设计牺牲了一些存储空间,但换来了极大的兼容性。

3. 数据清洗实录:上万处标点和重复条目是这样修掉的

3.1 初步去重:同一首诗以不同标题反复出现

整理过程中最大的噩梦是重复。同一首李白诗,在《全唐诗》里收录的是正题,但在《唐诗纪事》里可能换了标题或删了几句。如果只按"标题+作者"去重,基本没用。

我的策略是:按正文的"指纹"去重。具体做法:

import hashlib import json def poem_fingerprint(paragraphs): # 去掉所有非汉字字符,拼接后做 hash text = "".join(paragraphs) text = "".join(ch for ch in text if "\u4e00" <= ch <= "\u9fff") return hashlib.md5(text.encode("utf-8")).hexdigest()

两个关键点:

  • 用MD5而不是直接比对全文,是因为十万首诗做两两对比,字符串比较太慢,哈希可以提前索引;
  • 只保留汉字,去标点、去空格、去换行,是为了避免同一首诗因为标点处理方式不同被误判成两首。

指纹相同后,再人工确认保留哪一条:优先保留带注释的,标题更规范的,来自更权威合集的。

3.2 标点与断句规范化:全角、半角、弯引号

原始文本来源复杂,有从PDF转出来的、有从网页复制下来的、有扫描OCR的。标点问题千奇百怪:

  • 英文标点混入,比如用,代替
  • 弯引号(“”)和直引号("")混用;
  • 句末有的用,有的用.,有的干脆没有;
  • 常见的是断句错误:五言诗断成了"床前/明月光"、"疑是/地上霜"这样带斜杠的格式,或者两句并成一句。

我写了一个清洗管道,按顺序处理:

  1. 把所有全角英文字母、数字转半角;
  2. 把半角标点统一转全角(中文语境下句号、逗号、顿号、引号都该是全角的);
  3. 按"韵脚+句长"规则做断句校验:五言诗每句5个字、七言诗每句7个字,如果句子长度不对,就标记出来人工复核。

断句校验这个步骤特别有用。因为古诗词有严格的字数规律,一首七言绝句如果某句是8个字,那基本可以确定清洗有问题。

3.3 作者信息纠错与朝代补全

作者字段的坑比想象中多:

  • 同一作者多种署名:"李白"有时写作"李太白"、"青莲居士";
  • 生卒年跨朝代的人,归属争议大,比如李煜算"五代"还是"宋";
  • 部分佚名作品的作者字段是空的。

我的做法是维护一份作者规范映射表

{ "raw": "李太白", "canonical": "李白", "dynasty": "唐", "alias": ["青莲居士", "谪仙人"] }

先建立别名映射,再在清洗时做全量替换。朝代字段不依赖原始文本,而是以作者规范表为准,这样一来,"李煜"的作品默认为"五代",想看宋词的人即使不设置filter也基本不会混入。当然,这个方案不是完美的——我承认它在文学考证上有妥协,但对工程使用来说,它换来了可预期的确定性。

3.4 自动化校验:让十万首诗词的清洗结果可验证

清洗完不能直接打包发布,必须有一套校验规则:

  • 数量校验:每个合集的实际条数和预期条数对比,误差大于1%就报警;
  • 字段完整性:必填字段(id、title、author、paragraphs)为空的数据占比要低于0.1%;
  • 长度校验:五言诗的每句长度==5,七言诗每句长度==7,词牌不限制但上下句长度需要和词牌规则里的常见范围匹配;
  • JSON Schema校验:每个文件都用预定义的Schema检查字段类型是否正确。

这套校验脚本跑完之后,我打包前还会做一次抽样人工阅读:每个朝代随机抽20首,逐首读一遍,确认句子通顺、意境完整。机器校验防的是系统性错误,人工抽读防的是机器判断不了的"语义断裂"。

4. 压缩包目录详解:拿到手先看这几份文件

4.1 我的目录取舍:为什么不放SQL和CSV

确实有用户提过——"能不能同时给一份SQL?"我的答案是:JSON是源格式,其他格式你需要时自己转。原因很直接:

  • JSON是树形结构,可以直接表达"一首诗下面的多个句子、多个标签",而SQL要拆成多张表再join,怎么存都别扭;
  • CSV对于含换行、逗号、引号的文本字段是灾难——诗词正文里既有逗号又有引号,不做转义处理基本是坏的;
  • 目前Python、JavaScript、Java等主流语言处理JSON都是原生支持,解析开销可控。

压缩包里除了前面提到的JSON文件,还有一份README.md,里面写了:

  • 字段说明和取值枚举;
  • 更新日志和版本号;
  • 引用来源声明;
  • 常见使用示例。

4.2 三种常见语言的加载示例

Python(用于数据处理和脚本化使用)

import json with open("宋词.json", "r", encoding="utf-8") as f: data = json.load(f) # 筛选李清照的词 for poem in data["poems"]: if poem["author"] == "李清照": print(f"{poem['title']}: {poem['paragraphs'][0]}")

Node.js(用于前端或服务端)

const fs = require('fs'); const data = JSON.parse(fs.readFileSync('宋词.json', 'utf-8')); const liQingzhao = data.poems.filter(p => p.author === '李清照'); console.log(liQingzhao);

Java(用于Android或后端)

// 用 Jackson 解析 ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(new File("唐诗.json")); for (JsonNode node : root.get("poems")) { if ("李白".equals(node.get("author").asText())) { System.out.println(node.get("title").asText()); } }

5. 使用JSON数据时最容易踩的坑,以及我如何规避

5.1 编码问题:UTF-8带不带BOM差别很大

这是最隐蔽的一个坑。在Windows上,默认的记事本保存UTF-8文件时会自动加上BOM头(EF BB BF),这会导致JSON解析器直接报错或者解析出不可见字符。

  • Python的json.load遇到带BOM的文件会直接抛json.decoder.JSONDecodeError
  • Java的Jackson在部分版本下会遇到Invalid UTF-8的问题。

打包前我用脚本扫描了所有文件,把BOM全部去掉,统一为UTF-8无BOM。具体命令:

# Linux / macOS find . -name "*.json" -exec sed -i '1s/^\xEF\xBB\xBF//' {} \;

5.2 Java后端场景:大写字母开头的字段变小写

之前有读者问过我,解析后Title变成了title,查了半天不知道哪里出了问题。这是Jackson等JSON库的命名策略导致:如果Java Bean的字段是String Title,默认的camelCase策略会把它序列化成title,而如果JSON里本来就写了Title,反序列化时又匹配不上。

我在README里特别提醒了这一点:如果你们的后端接口要用@JsonProperty注解显式指定字段名,不要依赖默认命名策略:

public class Poem { @JsonProperty("id") public String id; @JsonProperty("title") public String title; @JsonProperty("author") public String author; @JsonProperty("paragraphs") public List<String> paragraphs; }

这样写最保险,不管把JSON文件喂给哪个JVM语言,字段映射都不会跑偏。

5.3 前端场景:"[object Object] is not valid JSON"的真相

很多网页在加载JSON时会在控制台报一个非常误导人的错:

Uncaught SyntaxError: "[object Object]" is not valid JSON

这个错误99%的情况是:你试图对一个JavaScript对象调用JSON.parse,而不是对字符串调用。比如:

const data = { title: "静夜思", author: "李白" }; // 错误写法:JSON.parse 接收了一个对象 const result = JSON.parse(data); // 正确写法 const result = JSON.parse(JSON.stringify(data)); // 或者如果是从外部 fetch 得来,response.json() 本身已经是解析后的对象 const result = await response.json();

如果发现报错中出现了[object Object],第一反应应该是去检查:传给JSON.parse的参数是不是一个对象,而不是一个字符串。

5.4 浏览器直接打开JSON文件的白屏问题

file://协议直接在Chrome或Edge里打开本地JSON并尝试用fetch加载,会被浏览器的同源策略拦下来,窗口一片空白。这和你的代码无关,是安全策略。

实际上,我在README里就对前端开发者做了如下建议:在本地开发时起一个简单的静态服务,而不是直接双击HTML文件。最简单的方式:

# 在项目根目录执行 python3 -m http.server 8080 # 然后浏览器访问 http://localhost:8080/index.html

这样fetch('唐诗.json')才能正常工作。

5.5 大JSON文件解析的性能问题

说句实话,即使是单朝的JSON,也有几十MB。老式做法是一次性JSON.parsejson.load全量读入,在小设备上确实可能卡顿或内存溢出。

我做了两件事来缓解:

  • 分文件存储,按需加载;
  • 在README里推荐流式解析方案。

Python端可以用ijson做流式解析;前端可以用fetch加流式读取(ReadableStream)或者做懒加载,在滚动到对应位置时才加载具体文件。

这个数据集毕竟不是为大数据场景设计的,如果你要做的是千万条的全文分析,建议先导入ClickHouse或MongoDB,再建立索引。不要让JSON文件本身承担数据库的职责。

6. 从JSON到应用:几个落地场景与我的扩展建议

6.1 全文搜索与条件筛选

拿到JSON后,最常见的需求就是"按作者查诗""按朝代筛选""按标签找主题"。最简单暴力的方式是加载后遍历过滤,数据量在十万级别时性能其实还能接受,但如果要做全文搜索(搜诗句中的某个词),建议导入Elasticsearch或SQLite的FTS5。

举个例子,用SQLite做诗句搜索:

CREATE VIRTUAL TABLE poems_fts USING fts5(title, author, paragraphs);

把JSON数据灌进去之后,搜"明月"只需要一条SQL,速度快很多。

6.2 随机诵读与每日推送

paragraphs设计成数组的好处在这个场景体现得很充分。做每日诗词卡片时,只需要:

  1. 加载对应朝代的JSON;
  2. 随机取一个index;
  3. paragraphs里按行渲染。

不需要再做任何字符串处理,直接交给前端展示。我自己的小工具还加了一个"飞花令"模式——给一个关键字,遍历所有诗句匹配包含该字的句子,paragraphs数组逐条匹配,逻辑非常简洁。

6.3 NLP分析与古诗生成

如果要做古诗风格分析,建议使用paragraphs_simple(简体版本)做向量化,保留的繁体字段做对照。注意一点:不要对平仄做自动推断,除非你清楚古音和今音的差异,否则拿普通话四声去套平仄,结果会很离谱。

6.4 我实际做完之后的几个体会

整理这套诗词JSON的过程,本质上是在做一次"内容工程"。它不像写业务代码那样有即时反馈,而是一个需要耐心校验和反复修正的过程。但做完之后,后续开发效率提升是肉眼可见的:

  • 新功能不再被数据清洗卡住,数据质量的可预期性非常高;
  • 出问题能快速定位到具体某一首诗的某一句,而不是在一堆txt里大海捞针;
  • 和其他项目对接时,直接甩一个README加JSON文件过去,别人照着示例就能跑通。

最后分享一个小技巧:发布数据包时,一定要在index.json里明确写一个"version": "1.0.0"字段。后来你会发现,这是整个包里性价比最高的一个字段——别人引用数据的时候能说清楚用的哪个版本,你更新数据的时候也不会引起下游一片乱。就这个字段,能省掉你至少十次解释"你用的为什么和我用的不一样"的沟通成本。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 11:51:12

嵌入式启动流程与OTA升级实战:从Cortex-M到U-Boot的故障定位方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 11:50:45

C语言实现英语信源熵与马尔科夫信源实验详解

简介&#xff1a;面向高校信息论课程、C语言学习与算法实践者&#xff0c;这份资源聚焦英语信源熵计算与一阶马尔科夫信源建模&#xff0c;覆盖课程设计中常见的“熵值求解序列生成”难题。压缩包共44个文件&#xff0c;整体约4.77MB&#xff0c;包含Visual Studio工程文件、C/…

作者头像 李华
网站建设 2026/9/9 11:50:05

2026降AI率工具实测:嘎嘎降AI、比话降AI、率零横向评测

2026年&#xff0c;AI写作助手几乎成了内容从业者的标配&#xff0c;但伴随而来的问题是&#xff1a;你辛辛苦苦让AI帮你列提纲、搭框架&#xff0c;最后一段文字发出去&#xff0c;平台后台的AI检测却直接给你标红。这段时间我密集测了三款号称能“降AI”的工具——嘎嘎降AI、…

作者头像 李华
网站建设 2026/9/9 11:49:40

Spring Boot + Vue 同城顺风车拼车系统核心设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 11:49:36

Spring Boot集成WebSSH:从浏览器直连服务器的完整实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 11:48:36

Windows文件权限完全指南:从NTFS权限到拒绝访问排查

大概每个用过Windows共享文件夹的人&#xff0c;都有过被"没有打开该文件的权限"这行提示拦住的经历。记得我还在公司做IT支持那会儿&#xff0c;接过一份很典型的问题单&#xff1a;财务部同事把报表放到共享目录&#xff0c;结果部门里一半人双击后直接弹出"请…

作者头像 李华