Files
PlantAI-rag/evaluation/UNIVERSAL_SUPPLEMENTARY_FETCHER.md
2026-07-10 17:59:59 +08:00

11 KiB
Executable File

通用补充材料获取系统设计方案

目标: 支持所有主流期刊的补充材料自动获取 愿景: 无论论文来自哪个期刊,都能自动获取完整的系统发育分组数据


🎯 核心问题

为什么需要通用方案?

期刊 补充材料位置 格式 当前支持
BMC系列 Europe PMC API ZIP+XLSX ✅ 已支持
Springer SpringerLink ZIP/PDF/XLSX ❌ 未支持
Elsevier ScienceDirect ZIP/XLSX ❌ 未支持
Wiley Wiley Online ZIP/XLSX ❌ 未支持
Nature Nature.com XLSX/PDF ❌ 未支持
PLOS PLOS ONE ZIP/XLSX ✅ 通过PMC支持
Frontiers Frontiers ZIP/XLSX ❌ 未支持
MDPI MDPI ZIP/XLSX ❌ 未支持

问题: 每个期刊都有自己的平台和API,没有统一标准


💡 解决方案

方案1: 多源适配器模式 (推荐)

class UniversalSupplementaryFetcher:
    """通用补充材料获取器"""
    
    def __init__(self):
        self.adapters = {
            'pmc': EuropePMCAdapter(),      # Europe PMC API
            'springer': SpringerAdapter(),  # SpringerLink
            'elsevier': ElsevierAdapter(),  # ScienceDirect API
            'wiley': WileyAdapter(),        # Wiley API
            'nature': NatureAdapter(),      # Nature API
            'direct': DirectDownloadAdapter(), # 直接下载链接
        }
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        """
        智能获取补充材料
        
        策略:
        1. 根据DOI/期刊名选择适配器
        2. 尝试获取
        3. 失败则尝试备用方案
        """
        journal = self.detect_journal(paper_info['doi'])
        
        # 主要方案
        adapter = self.adapters.get(journal)
        if adapter:
            result = adapter.fetch(paper_info)
            if result:
                return result
        
        # 备用方案: 爬虫
        return self.adapters['direct'].fetch(paper_info)

🔌 各期刊适配器设计

1. Europe PMC (已实现 ✅)

class EuropePMCAdapter:
    """Europe PMC API - 支持所有PMC收录期刊"""
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        pmcid = paper_info['pmcid']
        url = f"https://www.ebi.ac.uk/europepmc/webservices/rest/{pmcid}/supplementaryFiles"
        
        response = requests.get(url, timeout=120)
        if response.status_code == 200:
            return self.save_zip(response.content)
        return None
    
    def supports(self, doi: str) -> bool:
        """支持所有有PMCID的论文"""
        return has_pmcid(doi)

覆盖期刊: BMC, PLOS, Nature Communications, 所有PMC收录期刊


2. Springer (待实现)

class SpringerAdapter:
    """SpringerLink API"""
    
    API_BASE = "https://api.springernature.com"
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        doi = paper_info['doi']
        
        # 1. 获取文章元数据
        metadata = self.get_metadata(doi)
        
        # 2. 提取补充材料链接
        supp_urls = metadata.get('supplementaryMaterialUrls', [])
        
        # 3. 下载
        for url in supp_urls:
            if self.download(url):
                return True
        
        return None
    
    def supports(self, doi: str) -> bool:
        return 'springer' in doi or '10.1186' in doi

覆盖期刊: BMC系列, Springer系列


3. Elsevier (待实现)

class ElsevierAdapter:
    """ScienceDirect API"""
    
    API_KEY = "YOUR_API_KEY"  # 需要申请
    API_BASE = "https://api.elsevier.com/content"
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        doi = paper_info['doi']
        pii = self.doi_to_pii(doi)  # DOI转PII
        
        # ScienceDirect API
        url = f"{self.API_BASE}/article/pii/{pii}"
        headers = {"X-ELS-APIKey": self.API_KEY}
        
        response = requests.get(url, headers=headers)
        
        # 解析补充材料链接
        supp_links = self.parse_supplementary_links(response)
        
        # 下载
        return self.download_files(supp_links)
    
    def supports(self, doi: str) -> bool:
        return '10.1016' in doi  # Elsevier DOI前缀

覆盖期刊: Cell, ScienceDirect, 所有Elsevier期刊


4. Wiley (待实现)

class WileyAdapter:
    """Wiley Online Library"""
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        doi = paper_info['doi']
        
        # Wiley页面结构
        article_url = f"https://onlinelibrary.wiley.com/doi/{doi}"
        
        # 需要爬取页面获取下载链接
        html = requests.get(article_url).text
        supp_links = self.parse_supplementary_links(html)
        
        return self.download_files(supp_links)
    
    def supports(self, doi: str) -> bool:
        return '10.1111' in doi or '10.1002' in doi

覆盖期刊: Plant Journal, New Phytologist, 所有Wiley期刊


5. Nature (待实现)

class NatureAdapter:
    """Nature.com"""
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        doi = paper_info['doi']
        
        # Nature通常有PMCID,优先用Europe PMC
        if paper_info.get('pmcid'):
            return None  # 让EuropePMC处理
        
        # 否则爬取Nature页面
        article_url = f"https://www.nature.com/articles/{doi.split('/')[-1]}"
        html = requests.get(article_url).text
        
        # 解析补充材料
        supp_links = self.parse_supplementary_links(html)
        return self.download_files(supp_links)
    
    def supports(self, doi: str) -> bool:
        return '10.1038' in doi

覆盖期刊: Nature, Nature Plants, Nature Genetics, 所有Nature系列


6. 通用爬虫 (备用方案)

class DirectDownloadAdapter:
    """
    通用爬虫方案
    当API不可用时,直接爬取期刊网站
    """
    
    def fetch(self, paper_info: Dict) -> Optional[Path]:
        doi = paper_info['doi']
        
        # 解析DOI获取文章页面
        article_url = self.resolve_doi(doi)
        
        # 使用Playwright/Selenium爬取
        with sync_playwright() as p:
            browser = p.chromium.launch()
            page = browser.new_page()
            
            # 访问页面
            page.goto(article_url)
            
            # 查找补充材料链接
            supp_links = page.eval_on_selector_all(
                "a[href*='supplementary'], a[href*='additional']",
                "elements => elements.map(e => e.href)"
            )
            
            # 下载
            for link in supp_links:
                if self.is_excel_file(link):
                    return self.download(link)
        
        return None

🏗️ 系统架构

┌─────────────────────────────────────────────────────────┐
│           UniversalSupplementaryFetcher                  │
│                    (统一接口)                            │
└─────────────────────────────────────────────────────────┘
                          │
        ┌─────────────────┼─────────────────┐
        │                 │                 │
   ┌────▼────┐      ┌────▼────┐      ┌────▼────┐
   │  PMC    │      │ Springer│      │ Elsevier│
   │ Adapter │      │ Adapter │      │ Adapter │
   └────┬────┘      └────┬────┘      └────┬────┘
        │                 │                 │
   ┌────▼────┐      ┌────▼────┐      ┌────▼────┐
   │Europe   │      │Springer │      │Science  │
   │PMC API  │      │Link API │      │Direct   │
   └─────────┘      └─────────┘      └─────────┘
        │                 │                 │
        └─────────────────┼─────────────────┘
                          │
                   ┌────▼────┐
                   │ 统一输出 │
                   │ ZIP/XLSX│
                   └─────────┘

📊 覆盖率分析

按期刊覆盖率

期刊集团 论文占比 技术难度 预计时间
PMC收录 40% 低 已支持
Springer 15% 中 2-3天
Elsevier 25% 中 2-3天
Wiley 10% 中 2-3天
Nature 5% 低 1-2天
其他 5% 高 5-7天

总计: 95%覆盖率,开发时间约2周


🚀 实施计划

Phase 1: 核心架构 (本周)

  • Europe PMC (已完成)
  • 多适配器框架
  • 智能期刊检测
  • 失败重试机制

Phase 2: 主要期刊 (下周)

  • Springer适配器
  • Elsevier适配器
  • Wiley适配器
  • Nature适配器

Phase 3: 备用方案 (第3周)

  • 通用爬虫
  • 验证码处理
  • 反爬虫绕过

Phase 4: 优化 (第4周)

  • 缓存系统
  • 批量处理
  • 监控告警

💰 成本分析

免费方案

期刊 API 限制
Europe PMC 免费 无限制
Springer 免费 需要注册
PLOS 免费 无限制
PubMed Central 免费 无限制

需要付费

期刊 费用 限制
Elsevier $0-免费(学术) 需要API key
Wiley 需要协议 机构访问
Nature 通常免费 通过PMC

结论: 大部分可以免费实现


🎯 最终愿景

# 用户只需要提供DOI,系统自动处理一切
fetcher = UniversalSupplementaryFetcher()

result = fetcher.fetch({
    "doi": "10.1016/j.cell.2023.01.001",  # 任意期刊
    "gene_family": "SPL"
})

# 自动:
# 1. 识别期刊 (Elsevier)
# 2. 选择适配器 (ElsevierAdapter)
# 3. 获取补充材料
# 4. 解析Excel
# 5. 返回完整分组

🤔 关键决策

决策1: 优先级

建议优先级:

  1. PMC收录期刊 (40%覆盖率) ✅ 已完成
  2. Springer (15%覆盖率) - 高优先级
  3. Elsevier (25%覆盖率) - 高优先级
  4. Wiley (10%覆盖率) - 中优先级
  5. 其他 (10%覆盖率) - 低优先级

决策2: 技术栈

推荐:

  • 主要: API优先(稳定、快速)
  • 备用: Playwright爬虫(通用性强)
  • 缓存: Redis/本地文件

决策3: 错误处理

策略:
1. 尝试API
2. 失败则尝试备用API
3. 再失败则尝试爬虫
4. 还失败则标记为"需手动处理"

📋 下一步行动

需要你的决策:

  1. 是否继续扩展?

    • A: 是,实现通用系统
    • B: 否,只支持PMC期刊
    • C: 先测试当前v4,再决定
  2. 优先级?

    • A: Springer (BMC系列)
    • B: Elsevier (最大份额)
    • C: Wiley (植物学期刊多)
  3. 时间投入?

    • A: 全力投入 (2周完成)
    • B: 渐进式 (每周一个期刊)
    • C: 按需实现 (用到哪个做哪个)

设计方案: 2026-03-30 目标: 通用补充材料获取系统