mcpField
C
chembl-database-bioactivity

chembl-database-bioactivity

github.com/jaechang-hits数据与数据库38474 次安装6 天前更新
代码仓库

关于 chembl-database-bioactivity

chembl-database-bioactivity 是通过公开 REST API 查询 ChEMBL 化合物、靶点和生物活性数据的技能,面向药物发现与化学信息学研究。它使用 requests 即可调用 API,无需 SDK 或身份验证,并支持结构搜索及分页筛选。

主要功能

  1. 01按名称、编号和性质检索化合物
  2. 02查询靶点及生物活性记录
  3. 03按 SMILES 进行相似度与子结构搜索
  4. 04获取药物机制和适应症
  5. 05使用过滤条件和分页整理结果

适用场景

  1. 01查找特定靶点的抑制剂活性
  2. 02比较化合物系列的构效关系
  3. 03按药物相似性属性筛选分子
  4. 04检索已批准药物的机制与适应症

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill chembl-database-bioactivity

安装后在 Claude Code 中输入/chembl-database-bioactivity确认已加载。

详细介绍

ChEMBL 数据库 — 生物活性查询

为什么没有 SDK? chembl_webresource_client 包为公开、无需身份验证的 REST/JSON API(地址为 https://www.ebi.ac.uk/chembl/api/data/)提供了便捷的封装。当 SDK 不可用时,每项操作都可以通过普通的 requests 和 URL 参数复现。本 SKILL.md 全程使用 REST 接口,因此只要环境中安装了 requests,代码就能运行。Django 风格的筛选语法(field__icontains=…、field__lte=…、field__range=a,b)可作为 URL 查询参数使用。

概述

ChEMBL 是 EMBL-EBI 的生物活性分子数据库:包含 200 多万种化合物、1,900 多万条生物活性测量数据(IC50、Ki、EC50、Kd 等)以及 1.3 万多个靶点。地址为 https://www.ebi.ac.uk/chembl/api/data/ 的 REST API 返回 JSON(追加 .json),也支持 XML/YAML;无需身份验证,并支持通过 URL 参数使用 Django 风格的查询筛选,以及通过 page_meta.next 进行游标式分页。

适用场景

  • 按名称、ChEMBL ID 或理化性质查找化合物
  • 查询特定靶点的生物活性数据(IC50、Ki、EC50)
  • 使用 SMILES 执行相似性或子结构搜索
  • 获取药物作用机制和临床适应症
  • 识别针对某个靶点的抑制剂、激动剂或生物活性分子
  • 分析化合物系列中的构效关系(SAR)
  • 根据 Lipinski 五规则或其他类药性标准筛选分子
  • 如需进行通用化学信息学处理(SMILES 操作、指纹、描述符),请改用 rdkit-cheminformatics
  • 如需使用其他化合物数据库(NIH,覆盖范围更广),请改用 pubchem-compound-search

前置条件

  • Python 包:requests(唯一必需项)。可选:用于表格分析的 pandas。
  • 无需 API 密钥:ChEMBL 可免费访问。
  • 速率限制:未公布明确的硬性限制。基础设施为共享资源;在批量请求循环中,每次请求间加入 time.sleep(0.2-0.5);遇到 HTTP 429 时应退避。
pip install requests
# Optional, for DataFrame work:
pip install pandas

快速开始

import requests

BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Retrieve a molecule by ChEMBL ID
r = requests.get(f"{BASE}/molecule/CHEMBL25.json", timeout=15)
r.raise_for_status()
aspirin = r.json()
print(f"{aspirin['pref_name']}: MW={aspirin['molecule_properties']['mw_freebase']}")
# ASPIRIN: MW=180.16

# Search targets by full name (acronyms like 'EGFR' don't match pref_name — use full term)
r = requests.get(
    f"{BASE}/target.json",
    params={"pref_name__icontains": "epidermal growth factor receptor",
            "target_type": "SINGLE PROTEIN", "limit": 5},
    timeout=15,
)
targets = r.json()["targets"]
print(f"EGFR-like targets: {len(targets)}, first={targets[0]['target_chembl_id']}")

# Potent bioactivities: EGFR (CHEMBL203) IC50 <= 100 nM
r = requests.get(
    f"{BASE}/activity.json",
    params={"target_chembl_id": "CHEMBL203",
            "standard_type": "IC50",
            "standard_value__lte": 100,
            "standard_units": "nM",
            "limit": 5},
    timeout=30,
)
data = r.json()
print(f"EGFR IC50 ≤ 100 nM records: {data['page_meta']['total_count']}")

核心概念

筛选运算符(Django 风格,作为 URL 参数使用)

SDK 的 field__operator=value 语法与 URL 查询参数一一对应。使用 & 组合筛选条件。

运算符URL 格式URL 片段示例
__exactfield=valuetarget_type=SINGLE+PROTEIN
__iexactfield__iexact=valuepref_name__iexact=aspirin
__contains / __icontainsfield__icontains=valuepref_name__icontains=kinase
__startswith / __endswithfield__startswith=Epipref_name__endswith=nib
__gt / __gte / __lt / __ltefield__lte=100standard_value__lte=100
__rangefield__range=lo,himolecule_properties__mw_freebase__range=300,500
__infield__in=a,b,cstandard_type__in=IC50,Ki,Kd
__isnullfield__isnull=False(Python 的 False/True 字符串)pchembl_value__isnull=False
__regexfield__regex=…pref_name__regex=^EGF.*kinase$
__searchfield__search=…description__search=apoptosis

通过 requests.get(..., params={...}) 传入参数时,库会自动处理 URL 编码(包括 __range 和 __in 中的逗号)。

核心端点

所有端点都接受 .json、.xml 或 .yaml 后缀。以下默认使用 JSON。

端点 URL返回内容关键字段
/molecule/{chembl_id}.json按 ID 查询化合物pref_name、molecule_chembl_id、molecule_properties、molecule_structures
/molecule.json?<filters>搜索化合物分页的 molecules[]
/target/{chembl_id}.json按 ID 查询靶点pref_name、target_type、organism、target_components
/target.json?<filters>搜索靶点分页的 targets[]
/activity.json?<filters>生物活性记录分页的 activities[]
/assay.json?<filters>测定详情分页的 assays[]
/drug.json?<filters>已批准药物信息分页的 drugs[];支持 /drug/{chembl_id}.json
/mechanism.json?<filters>作用机制分页的 mechanisms[]
/drug_indication.json?<filters>治疗适应症分页的 drug_indications[]
/similarity/{smiles}/{tanimoto}.jsonTanimoto 相似度(0–100)分页的 molecules[],包含 similarity 字段
/substructure/{smiles}.json子结构搜索分页的 molecules[]
/image/{chembl_id}.svgSVG 结构图像二进制 SVG(非 JSON)
/molecule_form/{chembl_id}.json母体/盐形式molecule_forms[]
/protein_class.json蛋白质分类层级分层浏览
/document.json?<filters>文献来源记录分页的 documents[]
响应结构
{
  "page_meta": {
    "limit": 20,
    "offset": 0,
    "total_count": 12145,
    "next": "/chembl/api/data/activity.json?...&offset=20",
    "previous": null
  },
  "activities": [ /* or molecules[], targets[], etc. */ ]
}

遍历 page_meta.next(相对 URL,需加上前缀 https://www.ebi.ac.uk),直到其值为 null。

分子属性

每条记录的 molecule_properties 中可访问以下属性:

字段描述
mw_freebase分子量(游离碱)
full_mwt完整分子量(包括盐)
alogp计算得出的 LogP
hba氢键受体数
hbd氢键供体数
psa极性表面积
rtb可旋转键数
num_ro5_violationsLipinski 五规则违规数
ro3_pass是否符合三规则
cx_most_apka / cx_most_bpka最酸性/最碱性的 pKa
靶点信息字段
字段描述
target_chembl_idChEMBL 靶点标识符
pref_name首选(完整)靶点名称——缩写(如 “EGFR”)无法匹配;请使用拼写完整的名称
target_typeSINGLE PROTEIN、PROTEIN COMPLEX、ORGANISM 等
organism靶点生物(例如 Homo sapiens)
tax_idNCBI 分类 ID
target_components[]组成部分(UniProt 登录号、序列等)
生物活性数据字段
字段描述
standard_type活性类型:IC50、Ki、Kd、EC50 等
standard_value数值型活性值
standard_units单位:nM、uM 等
pchembl_value归一化的 -log10 活性值(>6 表示效力强)
activity_comment活性注释
data_validity_comment数据质量标记(分析前请检查)
potential_duplicate重复标记

核心 API

1. 分子查询
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# By ChEMBL ID
r = requests.get(f"{BASE}/molecule/CHEMBL25.json", timeout=15)
aspirin = r.json()
print(f"{aspirin['pref_name']}: MW={aspirin['molecule_properties']['mw_freebase']}")

# By name (case-insensitive substring)
r = requests.get(f"{BASE}/molecule.json",
                 params={"pref_name__icontains": "imatinib", "limit": 5},
                 timeout=15)
for mol in r.json()["molecules"]:
    print(f"  {mol['molecule_chembl_id']}  {mol.get('pref_name')!r}")

# By Lipinski-compliant property ranges
r = requests.get(f"{BASE}/molecule.json",
                 params={"molecule_properties__mw_freebase__range": "300,500",
                         "molecule_properties__alogp__lte": 5,
                         "molecule_properties__hba__lte": 10,
                         "molecule_properties__hbd__lte": 5,
                         "limit": 3},
                 timeout=15)
print(f"Lipinski-compliant total: {r.json()['page_meta']['total_count']}")
2. 靶点查询
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# By ChEMBL ID
r = requests.get(f"{BASE}/target/CHEMBL203.json", timeout=15)
egfr = r.json()
print(f"{egfr['pref_name']} ({egfr['organism']}) — type={egfr['target_type']}")

# Search by full name (NOT acronym) + type
r = requests.get(f"{BASE}/target.json",
                 params={"pref_name__icontains": "kinase",
                         "target_type": "SINGLE PROTEIN", "limit": 5},
                 timeout=15)
d = r.json()
print(f"Kinase SINGLE_PROTEIN targets: total={d['page_meta']['total_count']}")
for t in d["targets"][:5]:
    print(f"  {t['target_chembl_id']:12s} {t.get('pref_name')!r}  ({t['organism']})")

# By organism
r = requests.get(f"{BASE}/target.json",
                 params={"organism": "Homo sapiens", "limit": 3},
                 timeout=15)
print(f"Human targets: total={r.json()['page_meta']['total_count']}")
3. 生物活性数据
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Potent inhibitors for a target (EGFR = CHEMBL203)
r = requests.get(f"{BASE}/activity.json",
                 params={"target_chembl_id": "CHEMBL203",
                         "standard_type": "IC50",
                         "standard_value__lte": 100,
                         "standard_units": "nM",
                         "limit": 5},
                 timeout=30)
data = r.json()
print(f"EGFR IC50≤100nM: total={data['page_meta']['total_count']}")
for act in data["activities"][:5]:
    print(f"  {act['molecule_chembl_id']:14s} IC50={act['standard_value']} nM "
          f"pChEMBL={act.get('pchembl_value')}")

# All pChEMBL-tagged activities for a compound
r = requests.get(f"{BASE}/activity.json",
                 params={"molecule_chembl_id": "CHEMBL25",
                         "pchembl_value__isnull": "False",
                         "limit": 5},
                 timeout=30)
print(f"Aspirin pChEMBL activities: total={r.json()['page_meta']['total_count']}")

# Multiple activity types (CHEMBL240 = D2 dopamine receptor)
r = requests.get(f"{BASE}/activity.json",
                 params={"target_chembl_id": "CHEMBL240",
                         "standard_type__in": "IC50,Ki,Kd",
                         "limit": 5},
                 timeout=30)
print(f"D2 receptor IC50/Ki/Kd: total={r.json()['page_meta']['total_count']}")
4. 基于结构的搜索
import requests
from urllib.parse import quote
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Similarity search (Tanimoto ≥ 85%)
# Path-style endpoint: /similarity/{smiles}/{threshold}
# The SMILES MUST be URL-encoded (it contains '/', '(', ')' etc.)
aspirin_smiles = quote("CC(=O)Oc1ccccc1C(=O)O", safe="")
r = requests.get(f"{BASE}/similarity/{aspirin_smiles}/85.json",
                 params={"limit": 5}, timeout=30)
data = r.json()
print(f"Similar to aspirin (≥85% Tanimoto): total={data['page_meta']['total_count']}")
for m in data["molecules"][:5]:
    print(f"  {m['molecule_chembl_id']}  similarity={m.get('similarity')}")
# Substructure search
benzimidazole = quote("c1ccc2[nH]cnc2c1", safe="")
r = requests.get(f"{BASE}/substructure/{benzimidazole}.json",
                 params={"limit": 3}, timeout=30)
print(f"Benzimidazole substructure total: {r.json()['page_meta']['total_count']}")
5. 药物和作用机制数据
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Drug record (max clinical phase, ATC class, etc.)
r = requests.get(f"{BASE}/drug/CHEMBL941.json", timeout=15)   # imatinib
drug = r.json()
print(f"Imatinib max_phase={drug.get('max_phase')}")

# Mechanisms of action — note: not every drug has mechanism records.
# Imatinib (CHEMBL941) returns 0 mechanism rows; sunitinib (CHEMBL535) has many.
r = requests.get(f"{BASE}/mechanism.json",
                 params={"molecule_chembl_id": "CHEMBL535"}, timeout=15)
for m in r.json()["mechanisms"]:
    print(f"  {m['mechanism_of_action']} → target {m.get('target_chembl_id')}")

# Therapeutic indications
r = requests.get(f"{BASE}/drug_indication.json",
                 params={"molecule_chembl_id": "CHEMBL941", "limit": 5},
                 timeout=15)
for ind in r.json()["drug_indications"]:
    print(f"  {ind.get('mesh_heading')!r}  max_phase_for_ind={ind.get('max_phase_for_ind')}")
# SVG molecular structure image — direct binary response, NOT JSON
# Do NOT call /image/{cid}.json — that endpoint raises JSONDecodeError.
r = requests.get(f"{BASE}/image/CHEMBL25.svg", timeout=15)
r.raise_for_status()
with open("aspirin.svg", "w") as f:
    f.write(r.text)
print(f"Saved aspirin.svg ({len(r.text)} bytes, looks_svg={'<svg' in r.text})")

常见工作流

工作流 1:查找靶点抑制剂

注意: pref_name__icontains 会匹配拼写完整的名称。缩写(如 'EGFR' 或 'BRAF')会返回 0 条结果;请使用 'epidermal growth factor receptor' 或 'B-raf'(带连字符)。

import requests, pandas as pd, time
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Step 1: Resolve the target by full name
r = requests.get(f"{BASE}/target.json",
                 params={"pref_name__icontains": "B-raf",
                         "target_type": "SINGLE PROTEIN", "limit": 5},
                 timeout=15)
targets = r.json()["targets"]
human_braf = next(t for t in targets if t["organism"] == "Homo sapiens")
target_id = human_braf["target_chembl_id"]
print(f"Using {target_id} — {human_braf['pref_name']}")

# Step 2: Paginate all potent IC50 activities (cap at 500 for demo)
url = (f"{BASE}/activity.json"
       f"?target_chembl_id={target_id}"
       f"&standard_type=IC50"
       f"&standard_value__lte=100"
       f"&standard_units=nM"
       f"&pchembl_value__isnull=False"
       f"&limit=200")
records = []
while url and len(records) < 500:
    r = requests.get(url, timeout=30)
    r.raise_for_status()
    data = r.json()
    records.extend(data["activities"])
    nxt = data["page_meta"].get("next")
    url = f"https://www.ebi.ac.uk{nxt}" if nxt else None
    time.sleep(0.2)

df = pd.DataFrame(records)
df["standard_value"] = pd.to_numeric(df["standard_value"])
print(f"Retrieved {len(df)} potent {target_id} compounds")
print(df[["molecule_chembl_id", "standard_value", "pchembl_value"]].head(10))
工作流 2:分析已知药物
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Sunitinib (CHEMBL535) — has documented mechanisms + indications.
# Imatinib (CHEMBL941) sometimes returns 0 mechanism rows depending on ChEMBL release.
chembl_id = "CHEMBL535"

# Molecule record
m = requests.get(f"{BASE}/molecule/{chembl_id}.json", timeout=15).json()
print(f"Name: {m['pref_name']}")
print(f"MW  : {m['molecule_properties']['mw_freebase']}")

# Mechanisms
mechs = requests.get(f"{BASE}/mechanism.json",
                     params={"molecule_chembl_id": chembl_id},
                     timeout=15).json()["mechanisms"]
for mc in mechs:
    print(f"  Mechanism: {mc['mechanism_of_action']}")

# Indications
inds = requests.get(f"{BASE}/drug_indication.json",
                    params={"molecule_chembl_id": chembl_id, "limit": 5},
                    timeout=15).json()["drug_indications"]
for ind in inds:
    print(f"  Indication: {ind.get('mesh_heading')}  "
          f"(Phase {ind.get('max_phase_for_ind')})")

# Bioactivity record count
total = requests.get(f"{BASE}/activity.json",
                     params={"molecule_chembl_id": chembl_id,
                             "pchembl_value__isnull": "False",
                             "limit": 1},
                     timeout=30).json()["page_meta"]["total_count"]
print(f"Total bioactivity records (pChEMBL-tagged): {total}")
工作流 3:构效关系研究
import requests, pandas as pd, time
from urllib.parse import quote
BASE = "https://www.ebi.ac.uk/chembl/api/data"

# Step 1: Similar compounds to a lead (e.g., quinoline scaffold)
lead_smiles = "c1ccc2c(c1)cc(nc2N)c3ccc(cc3)NC(=O)c4ccccc4"
r = requests.get(f"{BASE}/similarity/{quote(lead_smiles, safe='')}/80.json",
                 params={"limit": 20}, timeout=30)
analogs = r.json()["molecules"]
print(f"Analogs found: {len(analogs)}")

# Step 2: Collect bioactivities for each analog
records = []
for compound in analogs[:20]:
    cid = compound["molecule_chembl_id"]
    acts = requests.get(f"{BASE}/activity.json",
                        params={"molecule_chembl_id": cid,
                                "standard_type": "IC50",
                                "pchembl_value__isnull": "False",
                                "limit": 20},
                        timeout=30).json()["activities"]
    for act in acts:
        records.append({
            "chembl_id": cid,
            "target": act.get("target_pref_name"),
            "IC50_nM": act.get("standard_value"),
            "pchembl": act.get("pchembl_value"),
            "mw":    (compound.get("molecule_properties") or {}).get("mw_freebase"),
            "alogp": (compound.get("molecule_properties") or {}).get("alogp"),
        })
    time.sleep(0.2)

df = pd.DataFrame(records)
if not df.empty:
    df["IC50_nM"] = pd.to_numeric(df["IC50_nM"])
    print(df.groupby("target")["IC50_nM"].describe())

常见示例

示例:虚拟筛选过滤器(Lipinski 五规则)
import requests
BASE = "https://www.ebi.ac.uk/chembl/api/data"
r = requests.get(f"{BASE}/molecule.json",
                 params={"molecule_properties__mw_freebase__range": "300,500",
                         "molecule_properties__alogp__lte": 5,
                         "molecule_properties__hba__lte": 10,
                         "molecule_properties__hbd__lte": 5,
                         "molecule_properties__num_ro5_violations": 0,
                         "limit": 1},
                 timeout=15)
print(f"Drug-like candidates: {r.json()['page_meta']['total_count']}")
示例:将活性数据分页导出为 CSV
import requests, pandas as pd, time
BASE = "https://www.ebi.ac.uk/chembl/api/data"

url = (f"{BASE}/activity.json"
       f"?target_chembl_id=CHEMBL203"
       f"&standard_type=IC50"
       f"&pchembl_value__isnull=False"
       f"&limit=500")
all_acts = []
while url:
    r = requests.get(url, timeout=60)
    r.raise_for_status()
    data = r.json()
    all_acts.extend(data["activities"])
    nxt = data["page_meta"].get("next")
    url = f"https://www.ebi.ac.uk{nxt}" if nxt else None
    time.sleep(0.3)

df = pd.DataFrame(all_acts)
df.to_csv("egfr_activities.csv", index=False)
print(f"Exported {len(df)} records → egfr_activities.csv")
示例:配置带重试机制的稳健会话
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def chembl_session(retries=3, backoff=1.0):
    s = requests.Session()
    s.headers.update({"Accept": "application/json"})
    s.mount("https://", HTTPAdapter(max_retries=Retry(
        total=retries, backoff_factor=backoff,
        status_forcelist=[429, 500, 502, 503, 504],
        allowed_methods=["GET"])))
    return s

session = chembl_session()
r = session.get("https://www.ebi.ac.uk/chembl/api/data/molecule/CHEMBL25.json", timeout=15)
print(r.json()["pref_name"])
示例:下载 SVG 结构图像
import requests
r = requests.get("https://www.ebi.ac.uk/chembl/api/data/image/CHEMBL25.svg", timeout=15)
r.raise_for_status()
with open("aspirin.svg", "w") as f:
    f.write(r.text)

关键参数

参数端点默认值说明
limit所有列表端点20每页大小;最大为 1000
offset所有列表端点0分页偏移量(或跟随 page_meta.next)
format所有端点json(通过 .json 后缀)也支持 .xml、.yaml
pref_name__icontains/target、/molecule—完整名称中的子字符串;不匹配缩写,请使用完整名称
target_chembl_id/activity—例如:CHEMBL203(EGFR)、CHEMBL240(D2 受体)
molecule_chembl_id/activity、/mechanism、/drug_indication—例如:CHEMBL25(阿司匹林)
standard_type/activity—IC50、Ki、Kd、EC50
standard_value__lte/activity—活性值上限(与 standard_units 搭配使用)
pchembl_value__isnull/activity—使用 "False" 要求数据带有 pChEMBL 标记
target_type/target—SINGLE PROTEIN、PROTEIN COMPLEX、ORGANISM、…
{tanimoto}(路径)/similarity/{smiles}/{tanimoto}—Tanimoto 阈值,范围为 0–100
{smiles}(路径)/similarity、/substructure—URL 编码的 SMILES(urllib.parse.quote(s, safe=""))

故障排除

问题原因解决方案
pref_name__icontains=EGFR(或 BRAF)返回 0 条结果ChEMBL 存储的是完整名称;不匹配缩写使用 "epidermal growth factor receptor";查询 BRAF 时,使用带连字符的 "B-raf"
mechanism.json?molecule_chembl_id=CHEMBL941 返回空结果并非每种药物在每个版本中都有机制记录(例如,当前数据中伊马替尼有 0 条记录)使用 CHEMBL535(舒尼替尼)或 CHEMBL192(西地那非)作为已知有数据的示例
/image/{cid}.json 出现 JSONDecodeError图像端点返回的是二进制数据,而非 JSON始终使用 .svg 或 .png 后缀:/image/{cid}.svg
/molecule/{id} 返回 404ChEMBL ID 格式无效ID 必须包含前缀:CHEMBL25,而非 25
相似性搜索返回 400SMILES 未编码(/ 会与 URL 路径冲突)进行 URL 编码:urllib.parse.quote(smiles, safe="")
next 页为空,但 total_count 更高已达到内部上限(使用 offset 分页时通常为 10000)缩小筛选范围(日期范围、靶标类别)并重新分页;或使用 ChEMBL FTP 下载获取超过 100K 条记录
HTTP 429 Too Many Requests请求过于密集添加 time.sleep(0.3);挂载 Retry 适配器(参见示例)
activity 记录中的单位混杂不同实验报告的单位为 nM / µM / % inhibition筛选 standard_units="nM",并优先使用 pchembl_value 进行跨实验比较
data_validity_comment 不为空数据整理标记(例如,“可能存在转录错误”“超出典型范围”)在进行 SAR / 回归分析前剔除这些行
活性记录重复同一测量值由多个来源报告检查 potential_duplicate=True 并去重

最佳实践

  • 使用 pchembl_value 进行跨研究比较——它会将 IC50/Ki/EC50 标准化为可比较的 -log10 刻度。
  • 计算汇总值前务必检查 data_validity_comment——带标记的行可能会使分布产生偏差。
  • 在活性查询中固定 standard_units="nM",避免混用 nM 和 µM。
  • 使用 page_meta.next 进行分页,不要手动递增 offset——该 URL 已包含正确的游标。
  • 在路径式端点(/similarity/{smiles}/...、/substructure/{smiles})中对 SMILES 进行 URL 编码,使用 urllib.parse.quote(smi, safe="")。
  • 批量处理时使用带重试适配器的 Session(参见 Recipe)——ChEMBL 可以处理相当大的流量,但偶尔会返回 502/503。
  • 对于超过 100K 条记录,优先使用 ChEMBL FTP 下载,而不是分页 API 调用。
  • 谨慎使用 pref_name__icontains 中的首字母缩写——EGFR、BRAF、HER2 都会返回 0 条结果。请使用完整术语,或通过 target_components__accession=<UniProt> 进行筛选。

相关技能

  • rdkit-cheminformatics — SMILES 操作、指纹、描述符
  • datamol-cheminformatics — 分子预处理与特征化
  • pubchem-compound-search — 备用化合物数据库(NIH;覆盖范围更广,但生物活性信息较少)
  • pdb-database — 通过 RCSB PDB REST API 获取 ChEMBL 靶点的 3D 结构
  • opentargets-database — 将 ChEMBL 药物-靶点证据与疾病关联相链接

参考资料

评论

支持 Markdown