Files
JspaceAI/scripts/fetch_textbook_pdfs.py

127 lines
6.1 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
"""从 ChinaTextbook 仓库下载人教版核心教材 PDF 并提取文本。
策略:
1. 选 30 本最重要的人教版教材(小学语文数学 + 初中核心科目)
2. 下载 PDF用 raw.githubusercontent.com
3. 用 pypdf 提取文本
4. 保存到 corpus/china_textbook/<科目>_<年级>.txt
"""
import json
import os
import sys
import time
import urllib.request
from pathlib import Path
from pypdf import PdfReader
import io
OUT_DIR = Path(__file__).parent.parent / 'corpus' / 'china_textbook'
OUT_DIR.mkdir(parents=True, exist_ok=True)
REPO = 'TapXWorld/ChinaTextbook'
BRANCH = 'master'
RAW_BASE = f'https://raw.githubusercontent.com/{REPO}/{BRANCH}/'
# 30 本核心教材(人教版/统编版)
SELECTED_PDFS = [
# 小学语文
'小学/语文/统编版-人民教育出版社/一年级/义务教育教科书·语文一年级上册.pdf',
'小学/语文/统编版-人民教育出版社/一年级/义务教育教科书·语文一年级下册.pdf',
'小学/语文/统编版-人民教育出版社/二年级/义务教育教科书·语文二年级上册.pdf',
'小学/语文/统编版-人民教育出版社/二年级/义务教育教科书·语文二年级下册.pdf',
'小学/语文/统编版-人民教育出版社/三年级/义务教育教科书·语文三年级上册.pdf',
'小学/语文/统编版-人民教育出版社/三年级/义务教育教科书·语文三年级下册.pdf',
'小学/语文/统编版-人民教育出版社/四年级/义务教育教科书·语文四年级上册.pdf',
'小学/语文/统编版-人民教育出版社/五年级/义务教育教科书·语文五年级上册.pdf',
'小学/语文/统编版-人民教育出版社/六年级/义务教育教科书·语文六年级上册.pdf',
# 小学数学
'小学/数学/人教版-人民教育出版社/一年级/义务教育教科书·数学一年级上册.pdf',
'小学/数学/人教版-人民教育出版社/二年级/义务教育教科书·数学二年级上册.pdf',
'小学/数学/人教版-人民教育出版社/三年级/义务教育教科书·数学三年级上册.pdf',
'小学/数学/人教版-人民教育出版社/四年级/义务教育教科书·数学四年级上册.pdf',
'小学/数学/人教版-人民教育出版社/五年级/义务教育教科书·数学五年级上册.pdf',
'小学/数学/人教版-人民教育出版社/六年级/义务教育教科书·数学六年级上册.pdf',
# 小学英语
'小学/英语/人教版-人民教育出版社/三年级/义务教育教科书·英语三年级上册.pdf',
'小学/英语/人教版-人民教育出版社/四年级/义务教育教科书·英语四年级上册.pdf',
'小学/英语/人教版-人民教育出版社/五年级/义务教育教科书·英语五年级上册.pdf',
# 小学科学
'小学/科学/人教版-人民教育出版社/一年级/义务教育教科书·科学一年级上册.pdf',
'小学/科学/人教版-人民教育出版社/三年级/义务教育教科书·科学三年级上册.pdf',
# 初中
'初中/语文/统编版-人民教育出版社/七年级/义务教育教科书·语文七年级上册.pdf',
'初中/语文/统编版-人民教育出版社/八年级/义务教育教科书·语文八年级上册.pdf',
'初中/语文/统编版-人民教育出版社/九年级/义务教育教科书·语文九年级上册.pdf',
'初中/数学/人教版-人民教育出版社/七年级/义务教育教科书·数学七年级上册.pdf',
'初中/数学/人教版-人民教育出版社/八年级/义务教育教科书·数学八年级上册.pdf',
'初中/英语/人教版-人民教育出版社/七年级/义务教育教科书·英语七年级上册.pdf',
'初中/物理/人教版-人民教育出版社/八年级/义务教育教科书·物理八年级上册.pdf',
'初中/化学/人教版-人民教育出版社/九年级/义务教育教科书·化学九年级上册.pdf',
'初中/生物学/人教版-人民教育出版社/七年级/义务教育教科书·生物学七年级上册.pdf',
'初中/历史/统编版-人民教育出版社/七年级/义务教育教科书·中国历史七年级上册.pdf',
]
def download_pdf(url: str) -> bytes:
"""下载 PDF 返回 bytes"""
req = urllib.request.Request(url, headers={
'User-Agent': 'Mozilla/5.0 (educational corpus fetcher)'
})
with urllib.request.urlopen(req, timeout=60) as resp:
return resp.read()
def extract_text(pdf_bytes: bytes) -> str:
"""从 PDF bytes 提取文本"""
try:
reader = PdfReader(io.BytesIO(pdf_bytes))
texts = []
for page in reader.pages:
t = page.extract_text()
if t:
texts.append(t.strip())
return '\n\n'.join(texts)
except Exception as e:
print(f" 提取失败: {e}")
return ''
def main():
total_chars = 0
success = 0
for i, pdf_path in enumerate(SELECTED_PDFS):
# 生成输出文件名
name = pdf_path.split('/')[-1].replace('.pdf', '').replace('义务教育教科书·', '')
out_file = OUT_DIR / f"{name}.txt"
if out_file.exists() and out_file.stat().st_size > 100:
print(f"[{i+1}/{len(SELECTED_PDFS)}] 跳过(已存在): {name}")
total_chars += out_file.stat().st_size
success += 1
continue
url = RAW_BASE + urllib.request.quote(pdf_path, safe='/')
print(f"[{i+1}/{len(SELECTED_PDFS)}] 下载: {name}...", end=' ', flush=True)
try:
pdf_bytes = download_pdf(url)
print(f"{len(pdf_bytes)//1024}KB", end=' ', flush=True)
text = extract_text(pdf_bytes)
if text:
out_file.write_text(text, encoding='utf-8')
print(f"{len(text)} 字符")
total_chars += len(text)
success += 1
else:
print("→ 无文本可能是扫描PDF")
except Exception as e:
print(f"失败: {e}")
time.sleep(1) # 礼貌延时
print(f"\n完成: {success}/{len(SELECTED_PDFS)} 成功, {total_chars} 字符")
print(f"保存到: {OUT_DIR}")
if __name__ == '__main__':
main()