yexingyangPDF / generate_data.py
quejing's picture
Upload 36 files
4cbd2e8 verified
Raw
History Blame Contribute Delete
6.22 kB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
一键抓取所有 HuggingFace 数据集的 PDF 直链,按分类+数量分片输出多个小 JSON 文件。
"""
import json, urllib.request, urllib.error, urllib.parse, time, os, sys, io, math
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
# 数据集配置
DATASETS = [
{"id": "long_meishi", "name": "长篇·美式", "genre": "normal", "length": "long", "layout": "meishi", "repo": "quejing/20000-meishi-pdf", "subPath": None},
{"id": "long_yingshi", "name": "长篇·英式", "genre": "normal", "length": "long", "layout": "yingshi", "repo": "quejing/20000-yingshi-pdf", "subPath": None},
{"id": "short_meishi", "name": "短篇·美式", "genre": "normal", "length": "short", "layout": "meishi", "repo": "quejing/small-meishi-pdf", "subPath": None},
{"id": "short_yingshi", "name": "短篇·英式", "genre": "normal", "length": "short", "layout": "yingshi", "repo": "quejing/small-yingshi-pdf", "subPath": None},
{"id": "zashu_meishi", "name": "杂书名著·美式", "genre": "zashu", "length": "long", "layout": "meishi", "repo": "quejing/zashuPDF", "subPath": "旧书美式PDF"},
{"id": "zashu_yingshi", "name": "杂书名著·英式", "genre": "zashu", "length": "long", "layout": "yingshi", "repo": "quejing/zashuPDF", "subPath": "旧书英式PDF"},
{"id": "zhongwen_meishi","name": "古典中文·美式", "genre": "zhongwen", "length": "long", "layout": "meishi", "repo": "quejing/zhongwenxiaoshuo", "subPath": "古典美式PDF"},
{"id": "zhongwen_yingshi","name": "古典中文·英式","genre": "zhongwen", "length": "long", "layout": "yingshi", "repo": "quejing/zhongwenxiaoshuo", "subPath": "古典英式PDF"},
]
BASE_URL = "https://huggingface.co"
API_BASE = "https://huggingface.co/api"
CHUNK_SIZE = 5000 # 每个分片最多5000条
def fetch_all_files(repo):
url = f"{API_BASE}/datasets/{repo}?full=true"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
resp = urllib.request.urlopen(req, timeout=120)
data = json.loads(resp.read().decode("utf-8"))
return data.get("siblings", [])
def build_pdf_list(siblings, sub_path, ds_info):
results = []
for sib in siblings:
fname = sib.get("rfilename", "")
if not fname.lower().endswith(".pdf"):
continue
if sub_path and not fname.startswith(sub_path + "/"):
continue
base_name = fname.rsplit("/", 1)[-1]
# 拼接直链 — 对路径中特殊字符做 URL 编码,防止 &、空格等引起问题
encoded_fname = urllib.parse.quote(fname, safe='/%')
direct_url = f"{BASE_URL}/datasets/{ds_info['repo']}/resolve/main/{encoded_fname}"
results.append([base_name, direct_url]) # 紧凑格式: [文件名, 下载链接]
return results
def main():
out_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
os.makedirs(out_dir, exist_ok=True)
# 索引文件:列出所有数据源及其分片信息
index = {"sources": []}
for idx, ds in enumerate(DATASETS):
print(f"[{idx+1}/{len(DATASETS)}] 正在获取: {ds['name']} ({ds['repo']})", flush=True)
try:
siblings = fetch_all_files(ds["repo"])
pdfs = build_pdf_list(siblings, ds["subPath"], ds)
total = len(pdfs)
chunks = math.ceil(total / CHUNK_SIZE) if total > 0 else 1
print(f" -> 找到 {total} 个 PDF,分 {chunks} 个文件", flush=True)
# 写分片文件
chunk_files = []
for ci in range(chunks):
chunk_pdfs = pdfs[ci * CHUNK_SIZE : (ci + 1) * CHUNK_SIZE]
chunk_name = f"{ds['id']}_{ci}.json"
chunk_path = os.path.join(out_dir, chunk_name)
# 紧凑JSON,不缩进,不用ensure_ascii
with open(chunk_path, "w", encoding="utf-8") as f:
json.dump(chunk_pdfs, f, ensure_ascii=False, separators=(',', ':'))
fsize = os.path.getsize(chunk_path)
print(f" -> {chunk_name}: {len(chunk_pdfs)} 条, {fsize:,} bytes", flush=True)
chunk_files.append({"f": chunk_name, "n": len(chunk_pdfs)})
index["sources"].append({
"id": ds["id"],
"name": ds["name"],
"genre": ds["genre"],
"length": ds["length"],
"layout": ds["layout"],
"repo": ds["repo"],
"total": total,
"chunks": chunk_files,
})
except Exception as e:
print(f" !! 错误: {e}", flush=True)
index["sources"].append({
"id": ds["id"],
"name": ds["name"],
"genre": ds["genre"],
"length": ds["length"],
"layout": ds["layout"],
"repo": ds["repo"],
"total": 0,
"chunks": [],
"error": str(e),
})
time.sleep(0.3)
# 写索引文件
idx_path = os.path.join(out_dir, "index.json")
with open(idx_path, "w", encoding="utf-8") as f:
json.dump(index, f, ensure_ascii=False, separators=(',', ':'))
# 汇总
total = sum(s["total"] for s in index["sources"])
total_chunks = sum(len(s["chunks"]) for s in index["sources"])
print(f"\n{'='*60}", flush=True)
print(f"完成! {len(index['sources'])} 数据源, {total} PDF, {total_chunks} 个分片文件", flush=True)
for s in index["sources"]:
print(f" {s['name']}: {s['total']} 个 ({len(s['chunks'])} 分片)", flush=True)
# 清理旧的单文件
old = os.path.join(os.path.dirname(os.path.abspath(__file__)), "pdf_data.json")
if os.path.exists(old):
os.remove(old)
print(f"\n已删除旧文件: pdf_data.json", flush=True)
print(f"\n数据目录: {out_dir}", flush=True)
if __name__ == "__main__":
main()