如何用Python提取PubMed XML文章字段并构建SQL数据库?
解决方案:用BioPython Entrez提取PubMed结构化摘要字段
关键背景:PubMed XML中Methods/Results的存储位置
PubMed的结构化摘要内容会放在<AbstractText>标签下,通过Label属性区分不同部分(比如Label="METHODS"、Label="RESULTS");非结构化摘要则没有单独拆分,只能从完整摘要里提取(或无法拆分)。另外,部分文献可能在<Article>节点下有<Methods>标签,但该字段并非所有文献都具备,优先级低于结构化摘要的对应部分。
完整Python实现步骤
1. 安装依赖
pip install biopython sqlalchemy
biopython:用于调用NCBI Entrez API并解析PubMed XMLsqlalchemy:用于快速构建SQL数据库(支持SQLite、MySQL等)
2. 核心代码实现
from Bio import Entrez from sqlalchemy import create_engine, Column, String, Text, Integer from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker import xml.etree.ElementTree as ET # 配置NCBI邮箱(必填,NCBI要求识别请求来源) Entrez.email = "your_email@example.com" # 定义SQL数据表模型 Base = declarative_base() class PubMedArticle(Base): __tablename__ = 'pubmed_articles' pmid = Column(String(20), primary_key=True) title = Column(Text) year = Column(Integer) doi = Column(String(100)) journal_name = Column(Text) first_author = Column(String(100)) abstract = Column(Text) methods = Column(Text) results = Column(Text) # 备注:PubMed公开API不提供全文内容,仅能获取摘要 content = Column(Text, default="PubMed仅提供摘要,无公开全文内容") # 初始化数据库(以SQLite为例,可替换为MySQL等) engine = create_engine('sqlite:///pubmed_db.sqlite') Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() def fetch_and_parse_pubmed(pmid_list): # 批量获取PubMed XML数据 handle = Entrez.efetch(db="pubmed", id=','.join(pmid_list), retmode="xml") xml_data = handle.read() handle.close() root = ET.fromstring(xml_data) for article in root.findall('.//PubmedArticle'): # 提取PMID pmid = article.find('.//PMID').text # 提取标题 title = article.find('.//ArticleTitle').text # 提取发表年份 pub_date = article.find('.//PubDate') year = pub_date.find('Year') year = year.text if year is not None else None # 提取DOI doi = None for id_info in article.findall('.//ArticleId'): if id_info.get('IdType') == 'doi': doi = id_info.text break # 提取期刊名 journal_name = article.find('.//Journal/Title').text # 提取第一作者 first_author = None author_list = article.findall('.//Author') if author_list: last_name = author_list[0].find('LastName').text fore_name = author_list[0].find('ForeName').text first_author = f"{last_name}, {fore_name}" # 提取完整摘要及结构化Methods/Results abstract = "" methods = "" results = "" abstract_texts = article.findall('.//AbstractText') for abs_text in abstract_texts: abs_content = abs_text.text or "" abstract += abs_content + "\n" # 按Label属性识别结构化部分 label = abs_text.get('Label') if label and label.upper() == "METHODS": methods = abs_content elif label and label.upper() == "RESULTS": results = abs_content # 若结构化摘要无Methods,尝试提取Article节点下的Methods字段 if not methods: article_methods = article.find('.//Methods') methods = article_methods.text if article_methods is not None else "" # 写入数据库 db_article = PubMedArticle( pmid=pmid, title=title, year=int(year) if year else None, doi=doi, journal_name=journal_name, first_author=first_author, abstract=abstract.strip(), methods=methods.strip(), results=results.strip() ) session.add(db_article) session.commit() print(f"成功处理{len(pmid_list)}篇文献,数据已存入数据库") # 示例调用:替换为目标PMID列表 if __name__ == "__main__": sample_pmids = ["31234567", "32109876"] fetch_and_parse_pubmed(sample_pmids)
关键注意事项
- Content字段说明:PubMed公开API仅提供摘要信息,不开放全文获取权限。若需全文,需通过付费数据库或PubMed Central(仅限开放获取文献)获取,超出公开API范围。
- 结构化摘要兼容性:并非所有文献都有拆分好的Methods/Results部分,非结构化摘要对应的字段会为空,此时可结合NLP工具从完整摘要中提取(需额外开发)。
- NCBI请求限制:NCBI对API请求频率有限制(每秒最多3次),批量处理大量文献时需添加延时(如
time.sleep(1)),避免被封禁。
内容的提问来源于stack exchange,提问作者Isa Gallego
相关产品推荐
相关产品推荐

