본문으로 바로가기
ai-automation2026년 4월 8일·조회 76

대규모 학술 논문 PDF 크롤링 시스템 구축기: 100만 건 데이터 수집 노하우

arXiv, PubMed 등 주요 논문 저장소에서 23만 건의 PDF를 자동 수집한 경험 공유

SP

SpacePlanning

SpacePlanning AI Team

## 왜 논문 PDF 크롤링이 필요한가 학술 연구, AI 모델 학습, 문헌 분석 등 다양한 목적으로 대량의 논문 데이터가 필요한 경우가 있습니다. 특히 자연어 처리(NLP)나 과학 문헌 분석 프로젝트에서는 수십만 건의 논문을 체계적으로 수집하고 관리하는 것이 핵심 과제입니다. 이 글에서는 arXiv, PubMed, bioRxiv 등 주요 논문 저장소에서 **98만 건의 메타데이터**와 **23만 건의 PDF 파일**(총 1TB)을 수집한 경험을 바탕으로 실무 노하우를 공유합니다. ## 주요 논문 데이터 소스별 특징 ### 1. arXiv (23만 건 수집) - **특징**: 물리학, 수학, 컴퓨터 과학 분야 프리프린트 저장소 - **장점**: 대부분의 논문이 PDF로 공개되어 있고, API와 bulk access 제공 - **주요 카테고리**: cs.CL(자연어처리) 3.8만 건, cs.CV(컴퓨터 비전) 3.6만 건, cs.LG(머신러닝) 2.9만 건 - **용량**: 688GB (평균 3-4MB/파일) ### 2. PubMed (67만 건 메타데이터) - **특징**: 생명과학 및 의학 분야 최대 데이터베이스 - **주의점**: 모든 논문이 오픈액세스는 아니므로 PMC(PubMed Central)에서 무료 제공 여부 확인 필요 - **수집률**: 전체 67만 건 중 28만 건에서 PDF URL 확보 (42%) ### 3. bioRxiv/medRxiv (7만 건) - **특징**: 생물학/의학 분야 프리프린트 - **장점**: 거의 모든 논문이 PDF 제공, 수집률 99% - **용량**: 319GB ## 크롤링 시스템 아키텍처 ### 1단계: 메타데이터 수집 ```python # arXiv API 활용 예시 import urllib.request import xml.etree.ElementTree as ET def fetch_arxiv_metadata(category, start_date): base_url = 'http://export.arxiv.org/api/query?' query = f'search_query=cat:{category}&start=0&max_results=1000' response = urllib.request.urlopen(base_url + query) data = response.read() root = ET.fromstring(data) papers = [] for entry in root.findall('{http://www.w3.org/2005/Atom}entry'): paper = { 'id': entry.find('{http://www.w3.org/2005/Atom}id').text, 'title': entry.find('{http://www.w3.org/2005/Atom}title').text, 'pdf_url': entry.find('{http://www.w3.org/2005/Atom}link[@title="pdf"]').get('href') } papers.append(paper) return papers ``` ### 2단계: PDF 다운로드 전략 **핵심 고려사항:** 1. **Rate Limiting**: 각 소스마다 요청 제한이 다름 - arXiv: 초당 1-3 요청 권장 - PubMed: API 키 없이는 초당 3 요청 제한 2. **재시도 로직**: 네트워크 오류, 일시적 장애 대응 ```python import time import requests from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.retry import Retry def download_pdf_with_retry(url, save_path): session = requests.Session() retry = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504]) adapter = HTTPAdapter(max_retries=retry) session.mount('http://', adapter) session.mount('https://', adapter) try: response = session.get(url, timeout=30, stream=True) with open(save_path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) return True except Exception as e: print(f"Download failed: {e}") return False finally: time.sleep(1) # Rate limiting ``` 3. **저장 구조**: 카테고리별 디렉토리 분류 ``` /papers/ ├── arxiv/ │ ├── cs.CL/ │ ├── cs.CV/ │ └── cs.LG/ ├── biorxiv/ └── medrxiv/ ``` ## 데이터베이스 설계 ```sql CREATE TABLE papers ( id SERIAL PRIMARY KEY, source VARCHAR(50), -- 'arxiv', 'pubmed', 'biorxiv' paper_id VARCHAR(100) UNIQUE, title TEXT, authors TEXT[], abstract TEXT, categories VARCHAR(50)[], pdf_url TEXT, pdf_path TEXT, -- 로컬 저장 경로 download_status VARCHAR(20), -- 'pending', 'completed', 'failed' created_at TIMESTAMP DEFAULT NOW(), downloaded_at TIMESTAMP ); CREATE INDEX idx_source ON papers(source); CREATE INDEX idx_categories ON papers USING GIN(categories); CREATE INDEX idx_download_status ON papers(download_status); ``` ## 모니터링 및 진행상황 추적 **일일 리포트 자동 생성:** ```python from datetime import datetime, timedelta def generate_daily_report(db_conn): today = datetime.now().date() yesterday = today - timedelta(days=1) query = f""" SELECT source, COUNT(*) as total, SUM(CASE WHEN pdf_url IS NOT NULL THEN 1 ELSE 0 END) as has_pdf_url, SUM(CASE WHEN download_status = 'completed' THEN 1 ELSE 0 END) as downloaded, SUM(CASE WHEN downloaded_at::date = '{today}' THEN 1 ELSE 0 END) as today_downloads FROM papers GROUP BY source """ # 결과를 마크다운 표로 변환 # ... ``` ## 실전 팁 ### 1. 텍스트 추출 자동화 PDF 다운로드와 동시에 텍스트 추출까지 수행하면 효율적입니다. ```python import PyPDF2 def extract_text_from_pdf(pdf_path): try: with open(pdf_path, 'rb') as f: reader = PyPDF2.PdfReader(f) text = '' for page in reader.pages: text += page.extract_text() return text except: return None ``` ### 2. 중복 방지 - 논문 ID를 UNIQUE 제약조건으로 설정 - 다운로드 전 파일 존재 여부 체크 ### 3. 디스크 용량 관리 - 1TB 규모의 데이터는 압축 고려 (gzip으로 30-40% 절감 가능) - 오래된/사용 빈도 낮은 파일은 cold storage로 이동 ## 법적/윤리적 고려사항 ⚠️ **반드시 확인해야 할 사항:** 1. **라이선스**: arXiv는 대부분 재배포 가능하지만, PubMed는 저널별로 다름 2. **robots.txt**: 크롤링 금지 여부 확인 3. **API 이용약관**: bulk download 정책 준수 4. **개인정보**: 저자 이메일 등 민감정보 수집 주의 ## 결론 대규모 논문 크롤링 프로젝트의 핵심은: ✅ **단계별 접근**: 메타데이터 → PDF URL → 다운로드 → 텍스트 추출 ✅ **안정성**: 재시도 로직, 에러 핸들링, 진행상황 추적 ✅ **확장성**: 카테고리별 분산 처리, 병렬 다운로드 ✅ **준수**: 각 플랫폼의 API 정책 및 라이선스 존중 23만 건 규모는 단일 서버에서도 충분히 처리 가능하지만, 100만 건 이상으로 확장할 경우 분산 큐(Celery, RabbitMQ) 도입을 고려해보세요. ### 다음 단계 - **전문 검색 엔진 구축**: Elasticsearch로 논문 검색 시스템 만들기 - **임베딩 벡터화**: 논문 내용을 벡터로 변환해 유사도 검색 구현 - **자동 분류**: 머신러닝으로 논문 카테고리 자동 태깅
#크롤링#논문수집#arXiv#PubMed#데이터파이프라인#Python#학술데이터
공유하기:

이 주제에 대해 더 알아보고 싶으신가요?

프로젝트 상담을 통해 맞춤형 솔루션을 제안받으세요.