genAI-Project / scripts /download_corpus.py
OGB2000's picture
Initial clean deployment
bf77be6
Raw
History Blame Contribute Delete
5.45 kB
"""
scripts/download_corpus.py
--------------------------
Download 100–200 scientific papers from arXiv in the NLP/LLM/RAG domain.
Saves PDFs to data/papers/ and metadata to data/metadata.jsonl.
Usage:
python scripts/download_corpus.py --max_results 150 --output_dir data/papers
"""
import argparse
import json
import time
import urllib.request
import urllib.parse
from pathlib import Path
import xml.etree.ElementTree as ET
ARXIV_QUERIES = [
"retrieval augmented generation large language models",
"RAG question answering transformer",
"dense retrieval natural language processing",
"LLM hallucination mitigation grounding",
"FAISS vector search semantic similarity",
"sentence transformers embeddings NLP",
"scientific question answering benchmark",
"knowledge-intensive NLP tasks",
]
ARXIV_API = "https://export.arxiv.org/api/query"
NS = {"atom": "http://www.w3.org/2005/Atom", "arxiv": "http://arxiv.org/schemas/atom"}
def search_arxiv(query: str, max_results: int = 25, start: int = 0) -> list[dict]:
params = urllib.parse.urlencode({
"search_query": f"all:{query}",
"start": start,
"max_results": max_results,
"sortBy": "relevance",
"sortOrder": "descending",
})
url = f"{ARXIV_API}?{params}"
with urllib.request.urlopen(url, timeout=30) as resp:
xml_data = resp.read()
root = ET.fromstring(xml_data)
papers = []
for entry in root.findall("atom:entry", NS):
arxiv_id_raw = entry.findtext("atom:id", default="", namespaces=NS)
arxiv_id = arxiv_id_raw.split("/abs/")[-1].strip()
title = (entry.findtext("atom:title", default="", namespaces=NS) or "").strip().replace("\n", " ")
abstract = (entry.findtext("atom:summary", default="", namespaces=NS) or "").strip().replace("\n", " ")
authors = [
a.findtext("atom:name", default="", namespaces=NS)
for a in entry.findall("atom:author", NS)
]
published = entry.findtext("atom:published", default="", namespaces=NS)
year = published[:4] if published else "unknown"
# PDF link
pdf_url = None
for link in entry.findall("atom:link", NS):
if link.get("type") == "application/pdf":
pdf_url = link.get("href")
break
if pdf_url is None and arxiv_id:
pdf_url = f"https://arxiv.org/pdf/{arxiv_id}"
papers.append({
"arxiv_id": arxiv_id,
"title": title,
"authors": authors,
"year": year,
"abstract": abstract,
"pdf_url": pdf_url,
})
return papers
def download_pdf(pdf_url: str, dest_path: Path) -> bool:
if dest_path.exists():
return True # already downloaded
try:
headers = {"User-Agent": "RAG-ScientificCorpus/1.0 (research project)"}
req = urllib.request.Request(pdf_url, headers=headers)
with urllib.request.urlopen(req, timeout=60) as resp:
dest_path.write_bytes(resp.read())
return True
except Exception as e:
print(f" ✗ Failed {pdf_url}: {e}")
return False
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--max_results", type=int, default=150)
parser.add_argument("--output_dir", type=str, default="data/papers")
parser.add_argument("--metadata_file", type=str, default="data/metadata.jsonl")
parser.add_argument("--sleep", type=float, default=3.0, help="Seconds between API calls")
args = parser.parse_args()
out_dir = Path(args.output_dir)
out_dir.mkdir(parents=True, exist_ok=True)
meta_path = Path(args.metadata_file)
seen_ids: set[str] = set()
all_papers: list[dict] = []
per_query = max(10, args.max_results // len(ARXIV_QUERIES))
for query in ARXIV_QUERIES:
if len(all_papers) >= args.max_results:
break
print(f"\n🔍 Querying: '{query}'")
try:
results = search_arxiv(query, max_results=per_query)
except Exception as e:
print(f" API error: {e}")
time.sleep(args.sleep * 2)
continue
for paper in results:
if paper["arxiv_id"] in seen_ids or not paper["arxiv_id"]:
continue
seen_ids.add(paper["arxiv_id"])
all_papers.append(paper)
if len(all_papers) >= args.max_results:
break
print(f" → {len(all_papers)} unique papers so far")
time.sleep(args.sleep)
print(f"\n📥 Downloading {len(all_papers)} PDFs to {out_dir}/ ...")
downloaded = 0
for i, paper in enumerate(all_papers):
safe_id = paper["arxiv_id"].replace("/", "_").replace(".", "_")
dest = out_dir / f"{safe_id}.pdf"
print(f" [{i+1}/{len(all_papers)}] {paper['title'][:60]}...")
ok = download_pdf(paper["pdf_url"], dest)
if ok:
paper["local_path"] = str(dest)
downloaded += 1
else:
paper["local_path"] = None
time.sleep(1.0) # be polite to arXiv
# Write metadata
with open(meta_path, "w", encoding="utf-8") as f:
for p in all_papers:
f.write(json.dumps(p, ensure_ascii=False) + "\n")
print(f"\n✅ Done. {downloaded}/{len(all_papers)} PDFs downloaded.")
print(f" Metadata saved to: {meta_path}")
if __name__ == "__main__":
main()