근거 기반 약물 추천을 위한 PubMed 논문 검색 및 분석 스크립트: 1. pubmed_search.py - PubMed 논문 검색 기본 템플릿 - Biopython Entrez API 활용 - 3가지 주제 검색 예시 포함 2. fetch_paper_abstract.py - PMID로 논문 초록 가져오기 - 특정 논문 상세 정보 조회 3. analyze_statin_myopathy.py - Statin 근육병증과 CoQ10 보충 연구 분석 - CK(Creatine Kinase) 측정의 의미 설명 4. ashwagandha_sleep_research.py - Ashwagandha의 수면 개선 효과 연구 - 작용 메커니즘 분석 (코르티솔, GABA) - 다른 수면 보조제와 비교 5. naproxen_advantages_research.py - Naproxen의 심혈관 안전성 연구 - NSAID 간 비교 분석 - 약동학 및 업셀링 시나리오 6. pycnogenol_multi_indication_research.py - 피크노제놀의 7가지 적응증 연구 - 발기부전, 당뇨망막병증, 정맥기능부전 등 - 우선순위 점수화 7. pycnogenol_womens_health_research.py - 피크노제놀의 여성 건강 효능 - 갱년기, 생리통, 피부 미용 8. sqlite_graph_example.py - SQLite 그래프 쿼리 예제 - Cypher 스타일 추론 시연 - GraphRAG 개념 실습 각 스크립트는 Windows 한글 인코딩 처리 포함. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
166 lines
5.2 KiB
Python
166 lines
5.2 KiB
Python
"""
|
|
PubMed 논문 검색 테스트
|
|
Biopython Entrez를 사용한 의학 논문 검색
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
|
|
# UTF-8 인코딩 강제 (Windows 한글 깨짐 방지)
|
|
if sys.platform == 'win32':
|
|
import io
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
|
|
|
from Bio import Entrez
|
|
from dotenv import load_dotenv
|
|
|
|
# .env 파일 로드
|
|
load_dotenv()
|
|
|
|
# NCBI Entrez 설정
|
|
Entrez.email = os.getenv('PUBMED_EMAIL', 'test@example.com')
|
|
api_key = os.getenv('PUBMED_API_KEY')
|
|
if api_key:
|
|
Entrez.api_key = api_key
|
|
print(f"[INFO] PubMed API Key 사용 중 (최대 10 req/sec)")
|
|
else:
|
|
print(f"[INFO] API Key 없음 (최대 3 req/sec 제한)")
|
|
|
|
|
|
def search_pubmed(query, max_results=5):
|
|
"""PubMed에서 논문 검색"""
|
|
try:
|
|
print(f"\n검색어: '{query}'")
|
|
print("-" * 80)
|
|
|
|
# 1. 검색 (PMID 목록 가져오기)
|
|
handle = Entrez.esearch(
|
|
db="pubmed",
|
|
term=query,
|
|
retmax=max_results,
|
|
sort="relevance"
|
|
)
|
|
record = Entrez.read(handle)
|
|
handle.close()
|
|
|
|
pmids = record["IdList"]
|
|
total_count = int(record["Count"])
|
|
|
|
if not pmids:
|
|
print(f"[WARNING] 검색 결과 없음")
|
|
return []
|
|
|
|
print(f"[OK] 총 {total_count}건 검색됨, 상위 {len(pmids)}건 조회 중...\n")
|
|
|
|
# 2. 논문 상세 정보 가져오기
|
|
handle = Entrez.efetch(
|
|
db="pubmed",
|
|
id=pmids,
|
|
rettype="medline",
|
|
retmode="xml"
|
|
)
|
|
papers = Entrez.read(handle)
|
|
handle.close()
|
|
|
|
results = []
|
|
|
|
for idx, paper in enumerate(papers['PubmedArticle'], 1):
|
|
try:
|
|
article = paper['MedlineCitation']['Article']
|
|
|
|
# PMID
|
|
pmid = str(paper['MedlineCitation']['PMID'])
|
|
|
|
# 제목
|
|
title = article.get('ArticleTitle', '(제목 없음)')
|
|
|
|
# 초록 (여러 섹션이 있을 수 있음)
|
|
abstract_parts = article.get('Abstract', {}).get('AbstractText', [])
|
|
if abstract_parts:
|
|
if isinstance(abstract_parts, list):
|
|
abstract = ' '.join([str(part) for part in abstract_parts])
|
|
else:
|
|
abstract = str(abstract_parts)
|
|
else:
|
|
abstract = "(초록 없음)"
|
|
|
|
# 저널
|
|
journal = article.get('Journal', {}).get('Title', '(저널 없음)')
|
|
|
|
# 출판 연도
|
|
pub_date = article.get('Journal', {}).get('JournalIssue', {}).get('PubDate', {})
|
|
year = pub_date.get('Year', '(연도 없음)')
|
|
|
|
# 저자 (첫 번째 저자만)
|
|
authors = article.get('AuthorList', [])
|
|
if authors:
|
|
first_author = authors[0]
|
|
last_name = first_author.get('LastName', '')
|
|
initials = first_author.get('Initials', '')
|
|
author_str = f"{last_name} {initials}" if last_name else "(저자 없음)"
|
|
else:
|
|
author_str = "(저자 없음)"
|
|
|
|
result = {
|
|
'pmid': pmid,
|
|
'title': title,
|
|
'abstract': abstract[:500] + '...' if len(abstract) > 500 else abstract,
|
|
'journal': journal,
|
|
'year': year,
|
|
'author': author_str
|
|
}
|
|
|
|
results.append(result)
|
|
|
|
# 출력
|
|
print(f"[{idx}] PMID: {pmid}")
|
|
print(f"제목: {title}")
|
|
print(f"저자: {author_str}")
|
|
print(f"저널: {journal} ({year})")
|
|
print(f"초록: {result['abstract']}")
|
|
print(f"링크: https://pubmed.ncbi.nlm.nih.gov/{pmid}/")
|
|
print("-" * 80)
|
|
|
|
except Exception as e:
|
|
print(f"[ERROR] 논문 파싱 실패: {e}")
|
|
continue
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
print(f"[ERROR] PubMed 검색 실패: {e}")
|
|
return []
|
|
|
|
|
|
def main():
|
|
"""메인 실행"""
|
|
print("=" * 80)
|
|
print("PubMed 논문 검색 테스트")
|
|
print("=" * 80)
|
|
|
|
# 테스트 1: Statin과 CoQ10 관계
|
|
print("\n[TEST 1] Statin과 CoQ10 근육 부작용 관계")
|
|
results1 = search_pubmed("statin AND coq10 AND muscle", max_results=3)
|
|
|
|
# 테스트 2: CoQ10 일반
|
|
print("\n[TEST 2] CoQ10 보충제 효능")
|
|
results2 = search_pubmed("coenzyme q10 supplementation benefits", max_results=3)
|
|
|
|
# 테스트 3: 약물 상호작용
|
|
print("\n[TEST 3] Atorvastatin 부작용")
|
|
results3 = search_pubmed("atorvastatin adverse effects", max_results=3)
|
|
|
|
print("\n" + "=" * 80)
|
|
print("검색 완료")
|
|
print("=" * 80)
|
|
print(f"총 {len(results1) + len(results2) + len(results3)}개 논문 조회됨")
|
|
print("\n[TIP] GraphRAG에 활용 방법:")
|
|
print(" 1. 검색된 PMID를 지식 그래프에 저장")
|
|
print(" 2. AI 추천 시 관련 논문 인용")
|
|
print(" 3. 예시: 'Statin 복용자에게 CoQ10 추천 (근거: PMID:12345678, 신뢰도: 85%)'")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|