4. Python 调用 Vina:subprocess 与 meeko 的基本用法

说实话,很多人刚开始做分子对接,习惯手工敲命令行。一个一个跑,一次一次等。我一开始也是这么干的,直到有一天我需要跑 200 个配体……嗯,从那天起,我就再也没手动敲过 Vina 命令行。

这一章,我们就聊聊怎么用 Python 把 Vina 管起来。你想想看,自动化之后,参数调试的效率完全不一样。

Python调用Vina:两种核心路径 subprocess 构建命令行字符串 调用 subprocess.run() 捕获 stdout/stderr 解析结果文件 meeko + meeko_docking 准备 SDF/SMI 配体 MoleculeSetup 生成 PDBQT + 构象 内嵌对接调用 参数批量扫描 结果自动汇总 并行加速对接 两条路径最终汇聚到:批量参数调试与自动化 选择策略取决于你 的输入格式与批量规模

4.1 subprocess:最直接的调用方式

Python 的 subprocess 模块,说白了就是让你能在 Python 里执行外部命令。Vina 本身就是个命令行工具,所以这个组合特别自然。

先看一个最基本的例子:

import subprocess

cmd = [
    "vina",
    "--receptor", "receptor.pdbqt",
    "--ligand", "ligand.pdbqt",
    "--out", "output.pdbqt",
    "--center_x", "0.0",
    "--center_y", "0.0",
    "--center_z", "0.0",
    "--size_x", "20",
    "--size_y", "20",
    "--size_z", "20",
    "--exhaustiveness", "8"
]

result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
我个人习惯把参数做成字典,再动态拼成列表结构。这样后面改参数特别方便,不用在 cmd 列表里挖来挖去。

4.2 捕获输出与解析结果

跑完对接,结果怎么拿?Vina 会把对接结果打印到标准输出,同时也写入输出文件。两种方式我都用过,但实际项目里我更推荐解析输出文件。

为什么?

# 来看看标准输出长什么样
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stderr)  # Vina 的进度信息在这里
print(result.stdout)  # 最终打分信息在这里

但 stdout 的格式不太稳定。不同版本的 Vina 输出格式可能微调。所以我一般这么做:

def parse_vina_score(pdbqt_file):
    """从 Vina 输出 PDBQT 中提取打分"""
    scores = []
    with open(pdbqt_file, 'r') as f:
        for line in f:
            if line.startswith('REMARK VINA RESULT:'):
                parts = line.split()
                # 格式: REMARK VINA RESULT: -9.5  0.0  0.0
                score = float(parts[3])
                scores.append(score)
    return scores
注意一下:Vina 的 PDBQT 输出文件里,REMARK VINA RESULT: 行可能有多个(多构象)。解析时记得循环全部找出来,别只读第一行。

4.3 批量处理的思路

单个文件没问题了,批量就好办了。我在项目中遇到过需要跑 1000+ 配体的场景,那时我是这样组织的:

import glob

ligands = glob.glob("ligands/*.pdbqt")
results = []

for lig in ligands:
    out_file = f"results/{lig.split('/')[-1]}"
    cmd = [
        "vina",
        "--receptor", "receptor.pdbqt",
        "--ligand", lig,
        "--out", out_file,
        # ... 其他参数
    ]
    subprocess.run(cmd, check=True)
    scores = parse_vina_score(out_file)
    results.append((lig, scores[0] if scores else None))

你想想看,这样一遍跑下来,所有打分都收集好了。再配个 pandas 导出 CSV,汇报数据直接就能用。

4.4 meeko 库:更优雅的配体准备

subprocess 虽然直接,但有个麻烦——配体得先转成 PDBQT。Vina 自带的 prepare_ligand4.py 脚本跑起来有点慢,而且对 SDF 格式支持不够好。

meeko 库就是来解决这个问题的。我第一次用 meeko 的时候,最惊艳的是它可以直接从 SDF 文件生成带构象的 PDBQT。省了 MGLTools 那套流程。

4.5 meeko 的基本用法

安装很简单:

pip install meeko

核心用法分三步:

from meeko import MoleculeSetup

# 1. 加载配体
setup = MoleculeSetup.from_sdf("ligand.sdf")

# 2. 生成可旋转键和构象
setup.expand_protonation_states()
setup.generate_conformers(n_conformers=10)

# 3. 写出 PDBQT
pdbqt_string = setup.write_pdbqt_string("ligand_output.pdbqt")
我个人经验是,n_conformers 设 10-20 个就够了。太多反而增加对接时间,打分提升不明显。

4.6 meeko 与 Vina 的整合

meeko 最有价值的地方,是它内置了对接调用的高层接口。你可以直接这么用:

from meeko_docking import MeekoDocking

docking = MeekoDocking(
    receptor="receptor.pdbqt",
    center=(0.0, 0.0, 0.0),
    box_size=(20, 20, 20),
    exhaustiveness=8
)

results = docking.dock_from_sdf("ligands.sdf")
for res in results:
    print(f"Ligand: {res.ligand_name}, Score: {res.score}")

嗯,这里要说明一下,meeko_docking 的接口还在迭代。我建议你还是以官方文档为准,但基本原理就是这样——它帮我们把 subprocess 那套流程封装了。

4.7 subprocess vs meeko:怎么选?

做一个简单对比,方便你选:

维度 subprocess meeko
输入格式 需要 PDBQT 直接支持 SDF/SMI
配体准备 自己额外处理 内置
批量处理 灵活,自由控制 方便,但自由度稍低
参数调试 完全手动控制 通过参数对象控制
学习成本 低 中(需了解 meeko 内部逻辑)

我个人的建议是:如果只是简单测试两个配体,subprocess 完全够用。但如果要做批量筛选、参数优化,meeko 能省不少代码。

4.8 实际项目中的避坑指南

最后分享几个我踩过的坑:

  • 路径问题:Vina 执行路径最好用绝对路径,或者确保在 PATH 里。我曾经被相对路径坑过一次,脚本在 IDE 里能跑,部署到服务器就找不到了。
  • 资源限制:并行跑 Vina 时注意 CPU 核数。subprocess 不会自动限流,我建议用 multiprocessing.Pool 控制并发数,避免把服务器跑挂。
  • meeko 版本兼容:meeko 更新较快,不同版本 API 可能有变化。建议在项目里固定版本号,比如 meeko==0.3.1。
  • 大文件处理:如果配体 SDF 文件特别大(上万分子),不要一次全部读进内存。用 meeko 的生成器模式 docking.dock_from_sdf_generator(),按批次处理。

核心要点:

  • subprocess 适合简单直接的单次或小批量调用
  • meeko 更适合大批量、复杂配体处理的场景
  • 解析结果时,文件解析比 stdout 解析更稳定
  • 批量处理一定要加并发控制,别让进程数超过 CPU 核心数

说白了,工具是死的,用活才是关键。subprocess 和 meeko 各有所长,理解了它们的原理,你就能根据项目需求灵活搭配。我自己做参数调试的时候,经常是 meeko 准备配体、subprocess 做精细控制,两者配合着用。