简介:一份面向中文古典诗词数据应用的《唐诗三百首》结构化数据集,涵盖320条诗歌记录,适合开发者快速搭建诗词查询库、教师制作教学课件,以及文本分析人员用作NLP语料;资源压缩包共4个文件,分别提供sql、json、csv、xlsx四种格式,sql可用于MySQL等数据库直接导入,json适合程序接口调用,csv便于数据筛选汇总,xlsx可让非技术用户直观编辑查看,包体仅141KB,轻量化设计让获取与部署都极为便利。目前已有1449人学习下载,数据虽规模不大,但已按统一的字段规则整理完毕,免去逐条手工录入古诗原文、作者和标题的繁琐工作。读者拿到后既可快速实现诗词检索、随机出题、爬虫测试等功能,也可在此基础上补充注释、译文、赏析或拼音,进一步扩展为完整的诗词学习系统与教学案例,整体是一份即取即用、质量可靠的基础数据包。
1. 唐诗三百首数据集:320条记录把一首诗拆成了四件事
拿到这个「数据库-唐诗三百首数据集」压缩包,第一印象是它小得不像话:41KB、320条记录,解压出来一堆 sql、json、csv、xlsx 文件。但真正把它跑起来之后,我的看法改了——这份数据集的看点恰恰在小。它不是那种塞了几万条噪音的古诗大杂烩,而是紧扣《唐诗三百首》这个经典选目的一份干净语料:每首诗都给你拆好了标题、作者、朝代、正文四个字段,直接喂给数据库课设、文本分析和信息检索项目都行。对正在写 MySQL 课程设计的学生来说,它就是一份能少走三天弯路的现成数据源;对做语料起步的开发者,它的字段组织和容量也适合当第一批测试数据。这份资源能解决的就是「我急着要一份规整唐诗数据」这件事,下面我把它拆开讲。
2. 压缩包里的五种实物:从 XLSX 阅读到 SQL 入库
2.1 五个文件先对号入座:哪个文件喂给哪个场景
解压唐诗三百首.zip后,看到的不是一堆散乱的 txt,而是四种后缀、五个文件,分别是tangshi300.json、tangshi300.xlsx、tangshi300.sql、tangshi300.csv以及打包时的原始压缩包。先别急着双击,每个文件的定位不一样,命名规则也遵循了常见的tangshi前缀加数字后缀的约定:
| 文件 | 格式定位 | 适合谁用 |
|---|---|---|
| tangshi300.csv | 通用表格文本,UTF-8 编码 | 小规模导入、Excel 阅读、ETL 中间格式 |
| tangshi300.json | 嵌套结构化数据,数组套对象 | Python、Node.js、前后端联调、接口模拟 |
| tangshi300.xlsx | 二进制表格,带格式 | 给学生交作业截图、快速人工浏览 |
| tangshi300.sql | 建表 + INSERT 语句 | 直接灌进 MySQL / MariaDB |
我拿到这份数据时,首先打开的不是 sql 而是 xlsx,目的是先看字段设计。Excel 打开后每一行的结构非常清晰:编号、标题、作者、朝代、正文。不少网上下载的唐诗数据集会把整首诗连标题一起塞进一个字段里,看起来省事,真正做检索时全是坑。这份数据把「标题」和「正文」拆开,好处是你可以直接按作者分组统计、按标题精确匹配、按正文做模糊查询——这正是数据库课设里最常见的三种查询需求。
2.2 字段拆分的逻辑:为什么古诗数据不能只存一列
现在很多学生拿到一份文本数据后第一个动作就是CREATE TABLE poem (content TEXT),把整首诗塞进去,结果做「按作者统计作品数量」时无从下手。再看这组数据的字段设计,按我的理解它至少做了三层考量:
第一层,主键独立。每条记录有独立编号,也就是 SQL 表里的自增主键,这样后续做批量修改、按行回滚都有锚点,不至于靠标题去重时被重名诗干扰。第二层,作者与朝代分别建字段。唐诗三百首里李白、杜甫、王维的作品各占多少,这类统计题在课设答辩中是必问项;如果作者信息和正文混在一个字段里,每次都要LIKE '%李白%',效率低而且容易误伤。第三层,正文保留完整格式。诗体、标点、换行符都按原始文本存放,不为省空间做截断,这是做文本分析的基本前提——数据集的价值不在于大,而在于每一行拿出来都能直接用。
3. 从 CSV 到 MySQL:建表、LOAD DATA 与三种课设查询
3.1 建表语句:为 320 条唐诗选合适的数据类型
有些同学拿到tangshi300.sql就直接source导入,这当然可以,但课设答辩老师经常追问「为什么用 VARCHAR(100) 而不是 TEXT」这类问题。所以我通常建议:即使有现成的 sql 文件,也要自己手写一遍建表语句,把类型设计逻辑搞明白。以下是我基于这份数据集结构整理出的常用建表方式:
CREATE TABLE tangshi300 ( id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键,从1开始递增', title VARCHAR(100) NOT NULL COMMENT '诗名,最长不超过100字符', author VARCHAR(50) NOT NULL COMMENT '作者名', dynasty VARCHAR(20) NOT NULL DEFAULT '唐' COMMENT '朝代', content TEXT NOT NULL COMMENT '正文,保留标点与换行', PRIMARY KEY (id), KEY idx_author (author), KEY idx_title (title(20)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;这段建表语句里我做了几个关键决定。id用INT UNSIGNED而不是BIGINT,是因为 320 条数据远未达到 int 上限,无符号还能留出更大的正数空间。title字段用VARCHAR(100)而不是TEXT,是因为短文本走索引更快,而且加上idx_title (title(20))前缀索引后,按标题查询的排序和匹配都更顺。author字段加了普通索引,这是为了后面做GROUP BY author统计时不走全表扫描。最后charset明确选utf8mb4——这是唯一能完整覆盖生僻字的编码,曾有人用utf8导入后才发现部分繁体字和古字变成问号。
3.2 LOAD DATA 导入:绕过 secure-file-priv 的两种办法
建好表后,导入动作我建议不使用INSERT INTO ... VALUES一条条写,320 条虽然不多,但手写 SQL 容易在引号和转义上翻车。推荐用 MySQL 自带的LOAD DATA命令:
LOAD DATA LOCAL INFILE '/path/to/tangshi300.csv' INTO TABLE tangshi300 CHARACTER SET utf8mb4 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES (title, author, dynasty, content);这里有几个参数必须说明。LOCAL关键字表示文件从客户端机器读取,而不是从服务器本地找,很多 vps 部署的 MySQL 默认开了secure-file-priv限制,不写 LOCAL 会直接报The used command is not allowed。CHARACTER SET utf8mb4指定文件编码,如果 CSV 的默认编码是 UTF-8 且不带 BOM,这里保持一致即可。FIELDS TERMINATED BY ','和ENCLOSED BY '"'是配套的,表示字段以逗号分割、字符串用双引号包裹。IGNORE 1 LINES跳过第一行表头。
如果LOAD DATA因为权限问题被拦截,我一般会退回两步方案:先用 Python 的 pandas 把 CSV 切成一段一段的多行 INSERT,再手工执行;或者干脆直接SOURCE tangshi300.sql。这份数据集里的 SQL 文件本身是完整的建表加插入语句组合,执行SOURCE命令是最省事的兜底方案,前提是表名和现有库中不冲突。
3.3 三种课设高频查询:从基础到分组合并验证数据
数据落库后,第一件事不是急着做炫酷的可视化,而是用三条 SQL 验证数据真实可用。第一条是「统计每位作者的作品数量」,这是《唐诗三百首》课设最常见的题目:
SELECT author, COUNT(*) AS cnt FROM tangshi300 GROUP BY author ORDER BY cnt DESC LIMIT 10;3.4 检查导入是否完整:行数、缺失值、字符集
SELECT COUNT(*) FROM tangshi300; -- 目标 320 SELECT * FROM tangshi300 WHERE content IS NULL OR content = ''; SELECT AUTHOR,COUNT(*) AS cnt FROM tangshi300 GROUP BY AUTHOR ORDER BY cnt DESC LIMIT 5; SELECT title, CHAR_LENGTH(content) AS len FROM tangshi300 ORDER BY len DESC LIMIT 5;执行结果里,最长的诗是《长恨歌》——840 字,这恰恰是「以数据验证常识」的典型例子:数据集字数分布符合唐诗常识,说明内容可信。若 across 各表和 column 的统计与你预期偏差过大,就要回到源文件重新清洗。320 条的体量在课堂上足够用,但若你要做深度学习,得先把这些字段拼成有上下文关联的序列——这就是第四章要讲的 JSON 加工。4. 把 JSON 加工成文本挖掘语料:一份可以直接跑的词频脚本
4.1 解析 JSON 结构:拿到作者、标题、正文字段
tangshi300.json的结构是标准的 JSON 数组,每个元素是一首诗。下面这段 Python 代码帮你把 320 首诗完整读进内存,顺便统计作者分布:
import json from collections import Counter with open('tangshi300.json', 'r', encoding='utf-8') as f: poems = json.load(f) print(f'总诗数: {len(poems)}') print(f'字段列表: {list(poems[0].keys())}') authors = Counter(p['author'] for p in poems) print('作品数最多的前5位作者:') for author, cnt in authors.most_common(5): print(f'{author}: {cnt}首')逻辑说明:json.load()把整个文件读成 Python 的 list,每个元素是 dict,字段名取自 JSON 的 key。这里我特意用Counter而不是自己写字典累加,是因为它有两行代码就完成分组计数的优势。参数说明:encoding='utf-8'必须与你保存 JSON 的编码一致,如果文件是从 Windows 下拷贝来的,可能要把编码改成utf-8-sig,否则第一个 key 会莫名带上\ufeff前缀。
4.2 生成汉字词频与最长诗统计:验证文本质量的两个手段
拿到结构化数据后,我一般先做两步验证:一是统计全量字数分布,二是算高频汉字。这两步都能快速判断有没有异常记录,比如某首诗的 content 字段是不是被截断了。
import re all_chars = [] for p in poems: text = p['content'] # 只保留中文字符,剔除标点、空格和换行 chars = re.findall(r'[\u4e00-\u9fff]', text) all_chars.extend(chars) p['char_count'] = len(chars) print(f'总汉字数: {len(all_chars)}') print(f'单首最多字数: {max(p["char_count"] for p in poems)}') print(f'单首最少字数: {min(p["char_count"] for p in poems)}') # 输出字频最高的10个汉字 from collections import Counter char_freq = Counter(all_chars) print('高频字 TOP 10:', char_freq.most_common(10))如果字数最多的诗达到几百字,说明是长篇叙事诗,比如《长恨歌》和《琵琶行》;如果字数最少的是五言绝句,正好 20 个字。这两类都正常。高频字里如果出现「之」「不」「人」这类文言虚词,说明语料是真实古诗而不是拼接垃圾数据——这在判断网络上下载的数据集是否「注水」时非常管用。
4.3 输出训练语料:转成 JSONL 或纯文本文件
做完清洗后,就可以把数据转成更适合喂给模型的格式。常见做法是把 JSON 转成 JSONL,每行一首诗,方便逐行读取。
with open('tangshi300_formatted.jsonl', 'w', encoding='utf-8') as f: for p in poems: line = json.dumps({ 'title': p['title'], 'author': p['author'], 'content': p['content'] }, ensure_ascii=False) f.write(line + '\n')ensure_ascii=False这一步非常关键。如果不设这个参数,json.dumps 默认会把所有中文转成\uXXXX转义序列,存进文件后全是英文代码。用 UTF-8 保存的话,还要保证读取时用的是同一个编码。想再进一步做机器学习的话,可以把每首诗拼接成「作者 + 标题 + 正文」的长序列,存成纯文本文件,一行一首,然后交给分词工具处理。
5. 导入避坑清单:BOM、乱码、主键错位与只导入 319 条的现场还原
5.1 现象一:导入后第一条记录的 id 变成了一个隐形的 239187
现象:用LOAD DATA导入tangshi300.csv后,执行SELECT * FROM tangshi300 LIMIT 1发现第一条记录的 id 非常长,像乱码。
原因:CSV 文件自带了 UTF-8 BOM 头。BOM 是藏在文件开头的一串隐形字节,MySQL 把它当成 id 字段内容的一部分。尤其从 Windows 记事本保存的 CSV 最容易带上 BOM。
解决:打开 CSV 后先检查前三个字节。我这里直接用 sed 处理:
sed -i '1s/^\xEF\xBB\xBF//' tangshi300.csv或者在LOAD DATA里加一句让 MySQL 忽略脏数据:
LOAD DATA LOCAL INFILE '/path/to/tangshi300.csv' INTO TABLE tangshi300 CHARACTER SET utf8mb4 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES (@id, title, author, dynasty, content) SET id = NULL;5.2 现象二:Excel 打开 CSV 全是乱码,但 xlsx 文件正常
现象:双击打开tangshi300.csv,中文全部变成乱码,而打开tangshi300.xlsx没问题。
原因:CSV 是 UTF-8 编码,Excel 在 Windows 上默认用 ANSI 编码打开。这是两边编码体系不一致导致的老问题,数据本身没问题。
解决:在 Linux 或 Mac 上可以用 vim 打开确认内容,或者用 Python 把 CSV 转成带 BOM 的 UTF-8:
with open('tangshi300.csv', 'r', encoding='utf-8') as f: content = f.read() with open('tangshi300_excel.csv', 'w', encoding='utf-8-sig') as f: f.write(content)转换后这个文件专门留给 Excel 用,MySQL 和 Python 里还是用原文件。平时练习的话,直接在 Excel 里选「数据 → 自文本/CSV」导入,指定 UTF-8 编码,也可以不看乱码。
5.3 现象三:LOAD DATA 执行后只导入了 319 条
现象:一条LOAD DATA命令执行完,提示成功,但COUNT(*)只返回 319。
原因:CSV 里某一行内容里带了换行符,而LINES TERMINATED BY '\n'把这个换行符当成了行结束标志,导致一条诗被拆成了两行,前一半有 id,后一半只有dynasty和content。
解决:把LINES TERMINATED BY '\n'改成LINES TERMINATED BY '\r\n',让每一行的结束符和实际文件保持一致。如果你读完 CSV 后发现某一行里包含天然的换行符,更稳妥的做法是改用FIELDS ENCLOSED BY '"'并配合OPTIONALLY ENCLOSED BY。我实际处理时会直接看第 319、320、321 行这三行内容,定位裂行具体发生在哪里,再做替换。
5.4 现象四:数据都导入了,但自增主键从 325 开始
现象:导入 320 条后,手动插入一条新的唐诗,id 不是 321,而是跳到了 325 或其他值。
原因:CSV 源文件里带了一个实际的 id 列,被LOAD DATA导入时覆盖了 MySQL 的自增主键。MySQL 的自增值在插入过显式 id 后会自动跳到「当前最大 id + 1」以上,不会回收中间的数字。
解决:如果想让自增重新连续,就在导入后重建表结构:
ALTER TABLE tangshi300 DROP id; ALTER TABLE tangshi300 ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;这种方法会打乱原有的 id 顺序,但在课设和演示场景里,连续的 id 比物理顺序重要。如果是生产环境,建议保留原来 id 不动,只调整自增起点:
ALTER TABLE tangshi300 AUTO_INCREMENT = 321;6. 用三条硬指标证明这套数据可信:做完这三件事你才能放心往下走
拿到任何数据集,第一件事都该验证质量,而不是急着写功能。这套唐诗数据我建议你跑掉下面三个检查,确认数据可用后再接模型或上网页。
6.1 编号连续性检查
ids = [p['id'] for p in poems] print(len(ids), min(ids), max(ids)) print('编号是否连续:', ids == list(range(min(ids), max(ids) + 1)))如果编号从 1 连续到 320,说明源文件没有删行、没有重复、没有合并导致的空洞。这个检查秒级完成,能筛掉大部分劣质数据集。
6.2 标题与作者去重检查
seen = set() dups = [] for p in poems: key = (p['title'], p['author']) if key in seen: dups.append(key) seen.add(key) print('重复记录数:', len(dups))《唐诗三百首》里有几首同题不同作者的诗,比如《秋夜曲》,所以光查 title 一定会误报重复;把 author 拼进来后就可靠了。去重维度选得对不对,直接影响后面统计结果的准确性。
6.3 字数分布写入表
import statistics counts = sorted(p['char_count'] for p in poems) print('最短:', counts[0], '最长:', counts[-1], '平均:', round(statistics.mean(counts), 1))如果最短 20 字、最长几百字、平均在 50~80 字之间,就证明文本结构完整——五言绝句、七言律诗、长篇叙事诗都齐。从那以后,我每拿到一份数据集,都强制先跑一遍这三项检查再言其他。320 条数据虽小,但字段规整、格式干净、来源明确,无论你是用它做数据库课程设计、Web 课设的数据接口,还是文本挖掘的练习语料,这套资源都值得下载放进自己的工具库。希望帮到你。
本文还有配套的精品资源,点击获取