Files
JspaceAI/scripts/fetch_corpus_incremental.py
XiuchengWu 81f6fd58e0 feat: add scripts for fetching and training educational corpus
- Implemented `fetch_corpus.py` to scrape Chinese educational content from Wikipedia, covering subjects like Chinese, Math, English, Chemistry, Politics, History, Geography, Physics, and Biology.
- Developed `fetch_corpus_incremental.py` for incremental fetching of missing entries, with automatic retries for rate limiting and support for resuming interrupted downloads.
- Created `train_chat.py` for training a dialogue model, including corpus cleaning, vocabulary management, and staged training with adaptive learning rates.
2026-07-07 17:42:24 +08:00

307 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""增量抓取九年义务教育全科目中文语料(维基百科 API
特性:
- 增量:已有词条跳过,只补缺失的
- 429 自动重试:等待 10 秒后重试,最多 5 次
- 长延时3秒防限流
- 每词条截取前 3000 字符
- 断点续传Ctrl+C 中断后再次运行会跳过已抓的
用法:
python scripts/fetch_corpus_incremental.py # 抓全部科目
python scripts/fetch_corpus_incremental.py 语文 数学 # 只抓指定科目
"""
import json
import urllib.request
import urllib.parse
import time
import re
import sys
from pathlib import Path
CORPUS_DIR = Path(__file__).parent.parent / 'corpus'
CORPUS_DIR.mkdir(parents=True, exist_ok=True)
# 九年义务教育各科目核心词条(覆盖小学到初中知识点)
SUBJECTS = {
'语文': [
# 古诗词与文言文(部编版教材重点篇目)
'静夜思', '春晓', '登鹳雀楼', '望庐山瀑布', '绝句', '春望',
'江雪', '游子吟', '清明', '枫桥夜泊', '寻隐者不遇',
'咏鹅', '回乡偶书', '咏柳', '凉州词', '出塞',
'芙蓉楼送辛渐', '送元二使安西', '九月九日忆山东兄弟',
'赠汪伦', '黄鹤楼送孟浩然之广陵', '望天门山',
'别董大', '早发白帝城', '赠花卿', '江南逢李龟年',
'春夜喜雨', '江畔独步寻花', '渔歌子', '塞下曲',
'望洞庭', '浪淘沙', '赋得古原草送别', '忆江南',
'悯农', '蚕妇', '陶者', '梅花', '元日',
'泊船瓜洲', '书湖阴先生壁', '六月二十七日望湖楼醉书',
'饮湖上初晴后雨', '题西林壁', '惠崇春江晚景',
'晓出净慈寺送林子方', '小池', '宿新市徐公店',
'春日', '观书有感', '题临安邸', '游园不值',
'乡村四月', '墨梅', '石灰吟', '竹石', '所见',
'村居', '己亥杂诗',
# 文言文
'论语', '孟子', '大学', '中庸', '诗经',
'世说新语', '聊斋志异', '西游记', '水浒传',
'三国演义', '红楼梦',
'岳阳楼记', '醉翁亭记', '爱莲说', '陋室铭',
'桃花源记', '小石潭记', '记承天寺夜游',
'送东阳马生序', '曹刿论战', '邹忌讽齐王纳谏',
'出师表', '陈涉世家',
# 作家
'李白', '杜甫', '白居易', '王维', '苏轼',
'李清照', '辛弃疾', '陆游', '鲁迅', '朱自清',
'老舍', '巴金', '冰心',
# 文学常识
'唐诗', '宋词', '元曲', '文言文', '成语',
],
'数学': [
'加法', '减法', '乘法', '除法', '四则运算',
'分数', '小数', '百分比', '比例', '方程',
'一元一次方程', '二元一次方程', '一元二次方程',
'不等式', '一元一次不等式',
'几何学', '三角形', '', '正方形', '长方形',
'平行四边形', '梯形', '多边形', '正方体', '长方体',
'圆柱', '圆锥', '', '扇形',
'面积', '体积', '周长', '角度', '',
'整数', '有理数', '无理数', '实数', '复数',
'代数', '函数', '一次函数', '二次函数', '反比例函数',
'勾股定理', '圆周率', '素数', '因数', '倍数',
'最大公约数', '最小公倍数', '绝对值', '平方根',
'统计', '概率', '平均数', '中位数', '众数',
'负数', '相反数', '倒数', '科学记数法',
'相似三角形', '全等三角形', '平行线',
'轴对称', '中心对称', '平移', '旋转',
'坐标', '直角坐标系', '象限',
],
'英语': [
'英文字母', '英语', '英语语法', '英语动词',
'英语名词', '英语形容词', '英语副词', '英语代词',
'英语介词', '英语连词', '英语冠词',
'英语时态', '一般现在时', '现在进行时',
'一般过去时', '过去进行时', '现在完成时',
'一般将来时', '过去完成时', '过去完成进行时',
'英语被动语态', '英语从句', '定语从句',
'名词性从句', '状语从句', '宾语从句',
'主语从句', '表语从句', '同位语从句',
'英语虚拟语气', '英语不定式', '英语动名词', '英语分词',
'英语单词', '英语发音', '英语拼写', '英语音标',
],
'化学': [
'化学', '化学元素', '元素周期表', '原子', '分子',
'离子', '化合物', '混合物', '纯净物', '单质',
'氧气', '氢气', '氮气', '二氧化碳', '一氧化碳',
'', '盐酸', '硫酸', '硝酸', '氢氧化钠',
'碳酸钙', '氯化钠', '碳酸氢钠', '氢氧化钙',
'', '', '', '氧化物', '过氧化物',
'化学反应', '化合反应', '分解反应', '置换反应',
'氧化还原反应', '复分解反应', '燃烧', '爆炸',
'溶液', '溶质', '溶剂', '溶解度', '浓度',
'金属', '合金', '', '', '', '', '',
'', '金刚石', '石墨', '有机化合物', '甲烷',
'乙醇', '乙酸', '蛋白质', '糖类', '脂肪',
'化学式', '化学方程式', '摩尔', '相对原子质量',
'原子结构', '电子', '质子', '中子', '同位素',
'化学键', '离子键', '共价键', '金属键',
],
'政治': [
'公民', '权利', '义务', '法律', '宪法',
'刑法', '民法', '消费者权益', '未成年人保护',
'人民代表大会制度', '全国人民代表大会',
'中国共产党', '社会主义', '社会主义市场经济',
'改革开放', '社会主义核心价值观',
'国家安全', '爱国主义', '集体主义',
'民主', '自由', '平等', '公正', '法治',
'民族团结', '一国两制', '和平共处五项原则',
'联合国', '世界贸易组织', '经济全球化',
'人民代表大会', '政治协商制度', '民族区域自治',
'基层群众自治', '依法治国', '以德治国',
],
'历史': [
'中国历史', '夏朝', '商朝', '西周', '东周',
'春秋时期', '战国时期', '秦朝', '西汉', '东汉',
'三国', '西晋', '东晋', '南北朝', '隋朝', '唐朝',
'宋朝', '辽朝', '金朝', '元朝', '明朝', '清朝',
'中华民国', '中华人民共和国',
'鸦片战争', '太平天国运动', '洋务运动', '甲午战争',
'戊戌变法', '义和团运动', '辛亥革命',
'新文化运动', '五四运动', '中国共产党成立',
'北伐战争', '土地革命', '长征',
'抗日战争', '解放战争', '新中国成立',
'丝绸之路', '四大发明', '郑和下西洋',
'孔子', '老子', '孟子', '庄子', '韩非子', '墨子',
'秦始皇', '汉武帝', '唐太宗', '宋太祖',
'成吉思汗', '朱元璋', '康熙帝',
'世界历史', '古埃及', '古希腊', '古罗马',
'文艺复兴', '工业革命', '第一次世界大战',
'第二次世界大战', '冷战', '欧洲联盟',
],
'地理': [
'地球', '地球仪', '经线', '纬线', '赤道',
'本初子午线', '时区', '国际日期变更线',
'大气层', '对流层', '水循环', '气候',
'热带', '温带', '寒带', '季风', '降水',
'地形', '平原', '高原', '山地', '盆地', '丘陵',
'河流', '湖泊', '海洋', '海峡', '岛屿', '半岛',
'中国地理', '中国行政区划', '省级行政区',
'长江', '黄河', '珠江', '淮河', '黑龙江',
'青藏高原', '内蒙古高原', '黄土高原', '云贵高原',
'塔里木盆地', '准噶尔盆地', '柴达木盆地', '四川盆地',
'华北平原', '东北平原', '长江中下游平原',
'喜马拉雅山脉', '昆仑山脉', '秦岭',
'北京', '上海', '广州', '深圳', '天津', '重庆',
'香港', '澳门', '台湾',
'世界地理', '亚洲', '欧洲', '非洲',
'北美洲', '南美洲', '大洋洲', '南极洲',
'太平洋', '大西洋', '印度洋', '北冰洋',
'撒哈拉沙漠', '亚马逊雨林', '尼罗河',
'人口', '城市', '农业', '工业', '交通运输',
],
'物理': [
'物理学', '', '运动', '速度', '加速度',
'牛顿运动定律', '牛顿第一定律', '牛顿第二定律',
'牛顿第三定律', '惯性', '质量', '密度',
'重力', '摩擦力', '弹力', '浮力', '压强',
'大气压强', '液体压强', '液压千斤顶',
'', '功率', '能量', '动能', '势能',
'机械能', '机械能守恒', '能量守恒定律',
'杠杆', '滑轮', '斜面', '轮轴',
'', '电荷', '电流', '电压', '电阻',
'欧姆定律', '串联', '并联', '电功率', '电能',
'', '磁场', '磁体', '电磁感应', '电磁铁',
'电动机', '发电机', '变压器',
'', '光的反射', '光的折射', '透镜',
'凸透镜', '凹透镜', '光的色散', '颜色', '光谱',
'声音', '声波', '音调', '响度', '音色',
'回声', '超声波', '次声波', '噪声',
'', '温度', '温度计', '熔化', '凝固',
'汽化', '液化', '升华', '凝华',
'比热容', '热传导', '热对流', '热辐射',
'物态变化', '沸腾', '蒸发', '内能',
'比热', '热量', '热机', '热机效率',
],
'生物': [
'生物学', '细胞', '细胞膜', '细胞核', '细胞质',
'细胞壁', '叶绿体', '线粒体', '染色体', 'DNA',
'基因', '遗传', '变异', '遗传学',
'光合作用', '呼吸作用', '新陈代谢',
'植物', '动物', '细菌', '病毒', '真菌',
'苔藓植物', '蕨类植物', '种子植物', '裸子植物', '被子植物',
'脊椎动物', '无脊椎动物', '哺乳动物', '鸟类',
'爬行动物', '两栖动物', '鱼类', '昆虫',
'生态系统', '食物链', '食物网', '生物多样性',
'生产者', '消费者', '分解者', '生物圈',
'人体', '心脏', '血管', '血液', '血液循环',
'', '呼吸', '肝脏', '', '',
'神经系统', '大脑', '脊髓', '神经元',
'消化系统', '吸收', '排泄', '泌尿系统',
'生殖', '发育', '青春期', '激素',
'群落', '种群', '生态系统稳定性',
'进化', '自然选择', '达尔文', '物种起源',
'组织', '器官', '系统', '细胞分裂', '细胞分化',
],
}
def fetch_extract(title: str, retries: int = 5) -> str:
"""从维基百科 API 获取词条纯文本摘要429 自动重试"""
api = "https://zh.wikipedia.org/w/api.php"
params = urllib.parse.urlencode({
'action': 'query',
'titles': title,
'prop': 'extracts',
'explaintext': '1',
'exsectionformat': 'plain',
'format': 'json',
'redirects': '1',
})
url = f"{api}?{params}"
for attempt in range(retries):
try:
req = urllib.request.Request(url, headers={
'User-Agent': 'JspaceAI/1.0 (educational corpus fetcher; contact@example.com)'
})
with urllib.request.urlopen(req, timeout=20) as resp:
data = json.loads(resp.read().decode('utf-8'))
pages = data.get('query', {}).get('pages', {})
for pid, page in pages.items():
if pid != '-1' and 'extract' in page:
return page['extract'][:3000] # 截取前 3000 字符
return '' # 词条不存在
except urllib.error.HTTPError as e:
if e.code == 429:
wait = 10 * (attempt + 1)
print(f" 429 限流,等待 {wait}s 后重试 ({attempt+1}/{retries})")
time.sleep(wait)
continue
else:
print(f" HTTP {e.code}: {title}")
return ''
except Exception as e:
print(f" 错误: {e}")
time.sleep(5)
return ''
def get_existing_titles(filepath: Path) -> set:
"""从已有文件读取已抓取的词条名"""
if not filepath.exists():
return set()
content = filepath.read_text(encoding='utf-8')
return set(re.findall(r'^## (.+)$', content, re.M))
def main():
subjects = sys.argv[1:] if len(sys.argv) > 1 else list(SUBJECTS.keys())
total_new = 0
total_skip = 0
for subject in subjects:
if subject not in SUBJECTS:
print(f"未知科目: {subject}")
continue
titles = SUBJECTS[subject]
out_file = CORPUS_DIR / f"{subject}.txt"
existing = get_existing_titles(out_file)
new_titles = [t for t in titles if t not in existing]
skip_count = len(existing)
print(f"\n{'='*60}")
print(f"[{subject}] 共 {len(titles)} 词条,已有 {skip_count},新增 {len(new_titles)}")
print(f"{'='*60}")
# 读取已有内容(追加模式)
if out_file.exists():
all_content = out_file.read_text(encoding='utf-8')
else:
all_content = f"=== {subject} ===\n"
for i, title in enumerate(new_titles):
print(f" [{i+1}/{len(new_titles)}] {title}...", end=' ', flush=True)
text = fetch_extract(title)
if text:
all_content += f"\n\n## {title}\n{text}\n"
print(f"{len(text)} 字符")
total_new += 1
else:
print("")
# 增量保存(每抓 5 条保存一次,防中断丢失)
if (i + 1) % 5 == 0:
out_file.write_text(all_content, encoding='utf-8')
time.sleep(3) # 长延时防限流
out_file.write_text(all_content, encoding='utf-8')
print(f"[{subject}] 完成,已保存到 {out_file.name}")
print(f"\n{'='*60}")
print(f"全部完成:新增 {total_new} 词条,跳过 {total_skip} 已有")
print(f"语料目录: {CORPUS_DIR}")
if __name__ == '__main__':
main()