用 BioPython 读取 PDB:安装、读取与遍历

处理 PDB 数据,肯定得有个趁手的工具。
我个人最喜欢的就是 BioPython。
你想想看,一个纯 Python 库,能读能写能分析,生态还特别好。
这一章咱们就把它的 PDB 模块搞熟。

先说个我自己的教训。
早年我做结构预处理时,用的全是手写字符串匹配,每次改格式都头大。
后来换到 BioPython,真的是省心太多。

安装 BioPython

安装这件事,其实简单。
只要你有 Python 环境,一行命令就搞定。

pip install biopython

如果你需要指定版本——我个人习惯用最新稳定版。

pip install biopython==1.83
小提示: 建议在虚拟环境里装,别搞乱全局包。 可以用 conda create -n pdb_workshop python=3.10,再装 BioPython。

读取 PDB 文件

BioPython 读取 PDB 文件有两个主要方式:PDBParser 和 MMCIFParser。
先说最常用的 PDBParser。

from Bio.PDB import PDBParser

parser = PDBParser()
structure = parser.get_structure("1ake", "1ake.pdb")

那句 get_structure 后面跟的两个参数:
第一个是 结构ID(你随便起),第二个是 文件路径。

我遇到过一个问题:
如果文件里的链名或残基编号不符合标准,parser 会报错。
这时候可以加一个 PERMISSIVE=True 参数,让它更宽容。

parser = PDBParser(PERMISSIVE=True)
避坑: PERMISSIVE 只是跳过某些错误记录,不会自动修正。 读取完后务必检查结构完整性。

如果你想读 mmCIF 格式,就换成 MMCIFParser。

from Bio.PDB import MMCIFParser

parser = MMCIFParser()
structure = parser.get_structure("1ake", "1ake.cif")

我个人建议:
如果能拿到 mmCIF,优先用 mmCIF。
因为它没有 PDB 格式的 80 列宽度限制,原子信息更完整。

结构对象层级

读懂 BioPython 的结构层级,是后续一切操作的基础。
说白了,BioPython 把 PDB 数据组织成一个树形结构。

  • Structure —— 最顶层,代表整个文件。
  • Model —— 模型,通常 NMR 结构会有多个。
  • Chain —— 链。
  • Residue —— 残基。
  • Atom —— 原子。

看看代码是怎么体现这个层级的。

# 获取第一个模型
model = structure[0]

# 获取所有链
for chain in model:
    print(f"Chain ID: {chain.id}")

    # 获取链里的所有残基
    for residue in chain:
        print(f"  Residue: {residue.resname} {residue.id[1]}")

        # 获取残基里的所有原子
        for atom in residue:
            print(f"    Atom: {atom.name}, coord: {atom.coord}")

这段代码会把每个原子坐标都打印出来。
我在项目中用过这个逻辑来提取特定残基的侧链原子。

遍历模型与链

大多数 X 射线晶体结构只有一个模型,但 NMR 结构可能有十几个。
这时候你必须遍历所有模型。

for model in structure:
    print(f"Model ID: {model.serial_num}")

    for chain in model:
        print(f"  Chain: {chain.id}")

为什么会这样?
因为 BioPython 的 structure[0] 默认只取第一个模型。
如果你不管 NMR,直接用索引取,会漏掉很多信息。

另外一个坑是我曾经踩过的:
有的 PDB 文件会包含 水分子链,链名叫 W(实际是水)。
你在处理时得判断是否要跳过。

for chain in model:
    # 跳过水分子链
    if chain.id == "W":
        continue
    process_chain(chain)

BioPython 没有内置的 HETATM 区分方法,但你可以通过残基名判断。
常见的水分子残基名:HOH、DOD、WAT。

记住: 遍历时一定要考虑 HETATM。 很多结构中的配体、金属离子都是 HETATM。

访问原子与残基属性

每个原子对象都有丰富的属性。
我常用的属性列表:

属性 含义
name 原子名称(如 CA、CB)
coord 三维坐标(numpy array)
bfactor 温度因子
occupancy 占位率
serial_number 原子序号
element 元素符号

举个例子:提取所有 Cα 原子的坐标。

ca_atoms = []
for model in structure:
    for chain in model:
        for residue in chain:
            if "CA" in residue:
                ca_atoms.append(residue["CA"].coord)

残基的属性也比较直观。

属性 含义
resname 残基名称(如 ALA)
id 残基编号和插入码(元组)
full_id 完整标识(含链名、模型等)
技巧: 如果你只需要特定残基类型(如所有 CYS), 可以用 residue.resname == "CYS" 做过滤。

知识体系图

下面这个 SVG 梳理了本章的核心流程。
用 BioPython 解析 PDB 文件,然后遍历结构层级,提取所需数据。

BioPython 解析 PDB 的知识体系 PDB 文件 PDBParser / MMCIFParser Structure 对象 Model Chain Residue Atom 常用属性访问 Atom.name / .coord / .bfactor / .occupancy | Residue.resname / .id 特征数据

这个图我就不多解释了。
你们跟着箭头走,就能理解从 PDB 文件到提取原子坐标的完整链路。

最后说一句

BioPython 的 PDB 模块很成熟,但并不意味着无脑用。
我遇到过一次:
某个老旧的 PDB 文件里有非标准残基名,解析直接挂了。
最后还得手写一个补丁来处理它。

所以,永远保留原始文件,永远做格式校验。
这是数据预处理的铁律。