做生物信息分析的朋友们都知道,NCBI数据库就像是一个巨大的生物数据宝库。但每次想批量下载蛋白或基因序列时,官方提供的Batch Entrez工具最多只能下载300条,这个限制对于需要处理海量数据的研究来说简直是杯水车薪。
我最近在做CAZy数据库相关研究时,需要下载300多万条蛋白序列。按照官方工具的速度,就算24小时不间断下载,也得花上好几个月。更糟的是,NCBI对未认证的请求还有严格的速率限制——每秒只能获取3条序列。这种效率,等数据下完课题都过期了。
这个Python库是我找到的宝藏工具,它可以直接通过accession number批量下载序列。安装特别简单:
bash复制pip install ncbi-acc-download
基本用法也很直观:
bash复制ncbi-acc-download --format fasta --m protein GCA_000005845
但真正厉害的是它的API集成能力。加上--api-key参数后,下载速率能从每秒3条提升到10条,这对于百万级数据量来说就是天壤之别。
Python的multiprocessing.Pool是实现并发的神器。在我的脚本中,我设置了10个进程同时工作:
python复制with Pool(processes=10) as pool:
results = [pool.apply_async(downlad_protein, (i,)) for i in protein_set]
这个数字不是随便定的——经过多次测试,10个进程既能最大化利用我的服务器资源,又不会触发NCBI的反爬机制。如果你的机器配置不同,可以适当调整这个参数。
假设你有一个像CAZy这样的TSV格式数据文件,提取accession number的代码是这样的:
python复制protein_set = set()
with open('cazy_data.txt', 'r') as fr:
for line in fr:
ncbi_protein = line.split('\t')[3].strip()
protein_set.add(ncbi_protein)
这里用集合(set)自动去重非常关键,能避免重复下载相同的序列。
每个下载任务都包装在try-except块中,确保单个失败不会影响整体流程:
python复制def downlad_protein(i):
run = f'ncbi-acc-download --format fasta --m protein {i} --api-key {api-key}'
try:
subprocess.run(run, shell=True)
# 后续处理...
except subprocess.CalledProcessError as e:
print(f"Error downloading {i}: {e}")
为了避免产生数百万个小文件,我设计了一个实时合并机制:
python复制if os.path.exists(f'{i}.fa'):
with open('cazy1.fasta', 'a') as outfile:
with open(f'{i}.fa', 'r') as infile:
outfile.write(infile.read())
subprocess.run(f'rm {i}.fa', shell=True)
这样最终只会得到一个整齐的FASTA文件,后续分析直接可用。
在NCBI官网申请API密钥是完全免费的,但很多人不知道这个功能。有了密钥后,记得把它保存在环境变量中,不要硬编码在脚本里:
python复制api_key = os.getenv('NCBI_API_KEY')
网络不稳定时,建议添加自动重试逻辑。我通常会这样实现:
python复制max_retries = 3
for attempt in range(max_retries):
try:
# 下载代码
break
except Exception as e:
if attempt == max_retries - 1:
raise
time.sleep(5)
长时间运行时要监控系统资源。我常用这段代码来防止内存泄漏:
python复制import psutil
if psutil.virtual_memory().percent > 90:
print("内存不足,暂停新任务")
pool.close()
pool.join()
同样的方法稍作修改就能用于下载基因组序列:
python复制run = f'ncbi-acc-download --format fasta --m nucleotide {i}'
这个脚本可以完美嵌入到Snakemake或Nextflow工作流中。比如在Snakemake规则里:
python复制rule download_sequences:
input:
"accessions.txt"
output:
"all_sequences.fasta"
run:
shell("python download_script.py")
对于需要持续更新的项目,可以记录已下载的accession number:
python复制downloaded = set()
if os.path.exists('downloaded.log'):
with open('downloaded.log', 'r') as f:
downloaded = set(f.read().splitlines())
new_items = protein_set - downloaded
如果遇到频繁超时,可以调整超时时间:
python复制subprocess.run(run, shell=True, timeout=120)
即使有API密钥,NCBI偶尔还是会限速。这时需要添加延迟:
python复制time.sleep(0.1) # 每个请求间隔100毫秒
在多用户服务器上运行时,注意设置正确的文件权限:
python复制os.chmod('cazy1.fasta', 0o644)
这套方法我已经在多个项目中成功应用,累计下载了超过2000万条序列。最近我正在试验用asyncio替代multiprocessing,初步测试显示性能还能提升30%左右。另一个改进方向是加入断点续传功能,这样即使脚本意外中断,也能从上次停止的地方继续下载。
对于超大规模数据(比如上亿条序列),可能需要考虑分布式方案。我测试过用Celery配合Redis作为任务队列,把下载任务分发到多台服务器上执行。不过这种架构就复杂多了,除非数据量真的特别大,否则单机多进程方案已经完全够用。