mcpField
P
pubchem-compound-search

pubchem-compound-search

github.com/jaechang-hitsデータ・データベース38471 回インストール1 週間前に更新
リポジトリ

pubchem-compound-search について

PubChem Compound Search は、公開 PUG-REST JSON API を通じて PubChem を検索する Python 向けスキルです。化学・生物医学のワークフローを対象とし、API キーなしで requests から識別子、物性、構造、同義語、アッセイ概要を取得します。

主な機能

  1. 01名称と化学識別子の解決
  2. 02化合物物性の一括取得
  3. 03類似性・部分構造検索
  4. 04同義語と説明の取得
  5. 05アッセイ概要の取得と構造のダウンロード

活用シーン

  1. 01化合物パネルの物性比較
  2. 02リード化合物の類似体検索
  3. 03特定の構造モチーフのスクリーニング
  4. 04後続解析用の構造ダウンロード

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill pubchem-compound-search

インストール後、Claude Code で/pubchem-compound-searchを入力して読み込まれたか確認します。

詳細

PubChem 化合物検索

概要

PubChem(NCBI)は、無料で利用できる最大の化学データベースです。化合物は 1 億 1,000 万件以上、物質は 2 億 8,000 万件以上、バイオアッセイ記録は数百万件あります。PUG-REST JSON API が標準的なプログラムインターフェースで、ここに示す例はすべて、通常の requests を使って直接呼び出します。Python の pubchempy ラッパーは必須ではありません。PUG-REST の URL 文法は十分に簡潔なため、直接呼び出すほうが動作がわかりやすく、リトライやキャッシュも容易で、サンドボックスの依存関係に関する問題も避けられます(このライブラリは TOOL_STATUS.md に含まれていません)。

URL の形式は固定されており、予測しやすいものです。

https://pubchem.ncbi.nlm.nih.gov/rest/pug/<input>/<operation>/<output>
  • <input> = compound/{name,cid,smiles,inchikey,formula}/<value>
  • <operation> = cids、property/<list>、synonyms、description、assaysummary、JSON(完全なレコード)、SDF、PNG
  • <output> = JSON、CSV、TXT、SDF、PNG

類似性検索、部分構造検索、分子式検索などの時間がかかる操作では、API は HTTP 202 と {"Waiting": {"ListKey": "..."}} を返します。IdentifierList が返されるまで compound/listkey/{key}/cids/JSON をポーリングしてください。このスキルでは、モジュール 4 でこのパターンを処理します。

使用する場面

  • 化合物名、SMILES、InChIKey、分子式で化合物を検索し、PubChem CID を取得する
  • 1 回のリクエストで、1 つまたは複数の CID の分子特性(分子量、XLogP、TPSA、水素結合ドナー/アクセプター数、回転可能結合数、分子式、IUPAC 名)を取得する
  • Tanimoto 類似度を使って構造が類似した化合物を検索する(非同期の ListKey ポーリング)
  • 特定の部分構造/ファーマコフォアモチーフを含む化合物を検索する
  • ある CID の同義語/商品名/CAS 番号をすべて取得する
  • 化合物のアッセイサマリーテーブル(スクリーニング結果の活性/不活性)を取得する
  • 1 回の API 呼び出しで識別子の形式を相互変換する(名前 ↔ CID ↔ SMILES ↔ InChI ↔ InChIKey)
  • 図や後続の RDKit 処理用に、2D SDF または PNG の構造データをダウンロードする
  • ローカルのケモインフォマティクス処理(フィンガープリント、記述子、3D コンフォーマー、骨格抽出)には rdkit を使用する
  • より詳細な生物活性/標的結合データ(特定の標的に対する IC50、Ki)には chembl-database-bioactivity を使用する

前提条件

  • Python パッケージ:requests、pandas — どちらも標準的な環境にすでに含まれています
  • API キーは不要 — PubChem は完全に公開されています
  • レート制限:IP あたり毎秒最大 5 リクエスト、毎分 400 リクエストです。ループ内では time.sleep(0.25) で間隔を空けてください。戻りコード 503 は、制限に達したことを示します。

requests と pandas がすでに利用できる pixi/conda 環境内にいる場合は、インストールを省略し、pixi run python ... でスクリプトを実行してください。

pip install requests pandas

クイックスタート

import requests

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

# name → CID
cid = requests.get(f"{BASE}/compound/name/aspirin/cids/JSON").json()["IdentifierList"]["CID"][0]

# CID → properties (single call, many fields)
r = requests.get(
    f"{BASE}/compound/cid/{cid}/property/"
    "MolecularWeight,XLogP,TPSA,HBondDonorCount,HBondAcceptorCount,SMILES,IUPACName/JSON")
p = r.json()["PropertyTable"]["Properties"][0]
print(f"CID {cid} — {p['IUPACName']}")
print(f"  MW={p['MolecularWeight']}  XLogP={p['XLogP']}  TPSA={p['TPSA']}")
print(f"  HBD={p['HBondDonorCount']}  HBA={p['HBondAcceptorCount']}")
print(f"  SMILES={p['SMILES']}")

コア API

モジュール 1:識別子の検索

/compound/{namespace}/{value}/cids/JSON を使って、外部識別子を PubChem CID に解決します。名前空間は name、cid、smiles、inchikey、inchi、formula です。

import requests
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

# By name (returns all matching CIDs as a list)
cids = requests.get(f"{BASE}/compound/name/caffeine/cids/JSON").json()["IdentifierList"]["CID"]
print(f"caffeine CIDs: {cids}")

# By canonical SMILES (URL-encode!)
smi = quote("CC(=O)OC1=CC=CC=C1C(=O)O", safe="")
cid = requests.get(f"{BASE}/compound/smiles/{smi}/cids/JSON").json()["IdentifierList"]["CID"][0]
print(f"aspirin SMILES → CID {cid}")

# By InChIKey (exact match, fastest if you already have one)
ikey = "BSYNRYMUTXBXSQ-UHFFFAOYSA-N"
cid = requests.get(f"{BASE}/compound/inchikey/{ikey}/cids/JSON").json()["IdentifierList"]["CID"][0]
print(f"InChIKey → CID {cid}")
モジュール 2:特性の取得

/compound/cid/{cid_or_csv}/property/<csv-list>/JSON は、指定したすべての特性を 1 回のリクエストで返します。CID と特性名はどちらも CSV 形式で連結できます。一度に最大約 200 個の CID と複数の特性をまとめて取得できます。

import requests

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

# Full property set for a single compound (ibuprofen CID 3672)
url = (f"{BASE}/compound/cid/3672/property/"
       "MolecularWeight,XLogP,TPSA,HBondDonorCount,HBondAcceptorCount,"
       "RotatableBondCount,SMILES,InChIKey,IUPACName,MolecularFormula/JSON")
p = requests.get(url).json()["PropertyTable"]["Properties"][0]
print(f"{p['IUPACName']}  formula={p['MolecularFormula']}")
print(f"  MW={p['MolecularWeight']} XLogP={p['XLogP']} TPSA={p['TPSA']}")
print(f"  HBD={p['HBondDonorCount']} HBA={p['HBondAcceptorCount']} RotB={p['RotatableBondCount']}")
import requests, pandas as pd

# Batch: 4 CIDs, 3 properties — one request, one round trip
cids = "2244,3672,2157,2662"   # aspirin, ibuprofen, naproxen, celecoxib
r = requests.get(
    f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cids}/property/"
    "MolecularWeight,XLogP,TPSA/JSON")
df = pd.DataFrame(r.json()["PropertyTable"]["Properties"])
print(df.to_string(index=False))
モジュール 3:同義語と説明

同義語(商品名、CAS 番号、別表記)と編集済みの説明は、/compound/{ns}/{value}/{synonyms|description}/JSON にあります。

import requests

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

# Full synonym list (aspirin has ~700)
info = requests.get(f"{BASE}/compound/cid/2244/synonyms/JSON").json()["InformationList"]["Information"][0]
print(f"aspirin synonyms: {len(info['Synonym'])}")
for s in info["Synonym"][:8]:
    print(f"  {s}")
import requests

# Curated descriptions (NCBI MeSH, CAMEO, etc.)
r = requests.get("https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/aspirin/description/JSON")
for item in r.json()["InformationList"]["Information"]:
    if "Description" in item:
        print(f"[{item.get('DescriptionSourceName','?')}]")
        print(f"  {item['Description'][:200]}…")
        print()
モジュール 4:類似性・部分構造検索(非同期 ListKey パターン)

構造検索では HTTP 202 と {"Waiting": {"ListKey": "..."}} が返されます。IdentifierList が返されるまで、約 2 秒ごとに /compound/listkey/{key}/cids/JSON をポーリングしてください。頻繁に使うため、ヘルパーでこの処理をまとめます。

import requests, time
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

def poll_listkey(listkey, max_polls=10, interval=2.0):
    """Block until PubChem finishes async search; return CID list."""
    for _ in range(max_polls):
        time.sleep(interval)
        j = requests.get(f"{BASE}/compound/listkey/{listkey}/cids/JSON", timeout=20).json()
        if "IdentifierList" in j:
            return j["IdentifierList"]["CID"]
    raise TimeoutError(f"ListKey {listkey} did not complete")

# Tanimoto similarity (90% threshold, max 20 hits) — starting from aspirin SMILES
smi = quote("CC(=O)OC1=CC=CC=C1C(=O)O", safe="")
init = requests.get(
    f"{BASE}/compound/similarity/smiles/{smi}/JSON?Threshold=90&MaxRecords=20").json()
cids = poll_listkey(init["Waiting"]["ListKey"]) if "Waiting" in init \
       else init["IdentifierList"]["CID"]
print(f"aspirin @90% similarity: {len(cids)} hits, sample={cids[:5]}")
import requests
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

# Substructure search — all compounds containing a sulfonamide group
smi = quote("S(=O)(=O)N", safe="")
init = requests.get(
    f"{BASE}/compound/substructure/smiles/{smi}/JSON?MaxRecords=20").json()
cids = poll_listkey(init["Waiting"]["ListKey"]) if "Waiting" in init \
       else init["IdentifierList"]["CID"]
print(f"sulfonamide-containing CIDs: {len(cids)}, sample={cids[:5]}")
モジュール 5:アッセイサマリー(生物活性データ)

/compound/cid/{cid}/assaysummary/JSON は、その化合物が登場する PubChem BioAssay をすべて含む Table を返します(アッセイ AID、標的、結果、利用可能な場合はマイクロモル単位の活性)。

import requests, pandas as pd

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

r = requests.get(f"{BASE}/compound/cid/2244/assaysummary/JSON", timeout=30)
rows = r.json().get("Table", {}).get("Row", [])
cols = r.json().get("Table", {}).get("Columns", {}).get("Column", [])
print(f"aspirin appears in {len(rows)} bioassays")

# First few columns + rows as a DataFrame
df = pd.DataFrame([row["Cell"] for row in rows[:5]], columns=cols)
print(df.iloc[:, :6].to_string(index=False))
モジュール 6:構造ファイルのダウンロード(SDF/PNG)

/compound/cid/{cid}/SDF は 2D MOL/SDF を返し、/compound/cid/{cid}/PNG は構造画像を返します(高解像度にするには ?image_size=large を使用します)。

import requests

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"
cid = 2519   # caffeine

# 2D SDF for downstream RDKit / OpenBabel
sdf = requests.get(f"{BASE}/compound/cid/{cid}/SDF", timeout=15).text
with open("caffeine.sdf", "w") as f:
    f.write(sdf)
print(f"caffeine.sdf: {len(sdf)} chars, ends with M  END={'M  END' in sdf}")

# PNG structure image
png = requests.get(f"{BASE}/compound/cid/{cid}/PNG?image_size=large", timeout=15).content
with open("caffeine.png", "wb") as f:
    f.write(png)
print(f"caffeine.png: {len(png)} bytes")

主な概念

非同期 ListKey パターン

類似性、部分構造、分子式の検索は非同期です。API はバックグラウンドジョブを開始し、{"Waiting": {"ListKey": "<id>"}} を伴う HTTP 202 を返します。IdentifierList を含むレスポンスが返るまで、約 2 秒ごとに /compound/listkey/{id}/cids/JSON をポーリングしてください。ほとんどの検索は 5~15 秒で完了します。小規模な検索ではポーリング間隔を短くし、非常に大規模な検索では長くしてください。すべての箇所で、Module 4 の poll_listkey ヘルパーを使用してください。

高速な検索のごく一部では、最初の呼び出しで Waiting フィールドなしに IdentifierList が直接返されます。どちらの場合にも対応できるよう確認してください。

プロパティ名のリファレンス
API 名意味
MolecularWeight分子量(g/mol、文字列)
MolecularFormulaヒル方式の分子式
SMILES立体化学情報を含む異性体 SMILES(2025 年以降の名称。以前は IsomericSMILES)
ConnectivitySMILES立体化学情報を含まない、結合情報のみの SMILES(2025 年以降の名称。以前は CanonicalSMILES)
IUPACName精選された IUPAC 名
InChI / InChIKeyIUPAC InChI / InChIKey
XLogP計算値の logP(オクタノール/水)
TPSAトポロジカル極性表面積(Ų)
HBondDonorCount水素結合ドナーの数
HBondAcceptorCount水素結合アクセプターの数
RotatableBondCount回転可能結合の数
HeavyAtomCount水素以外の原子数
Charge形式電荷

任意の項目を選んで CSV 形式で結合し、単一の /property/<csv>/JSON URL で取得できます。MolecularWeight は文字列として返されるため、計算の前に float に変換してください。

レスポンスのエンベロープ形式
  • cids/JSON → {"IdentifierList": {"CID": [int, ...]}}
  • property/.../JSON → {"PropertyTable": {"Properties": [{...}, ...]}}(入力順に、CID ごとに 1 つの辞書)
  • synonyms/JSON → {"InformationList": {"Information": [{"CID": int, "Synonym": [str, ...]}]}}
  • description/JSON → {"InformationList": {"Information": [{"CID": int, "Description": str, "DescriptionSourceName": str, ...}, ...]}}
  • assaysummary/JSON → {"Table": {"Columns": {"Column": [...]}, "Row": [{"Cell": [...]}, ...]}}
  • 非同期開始(類似性、部分構造、分子式) → {"Waiting": {"ListKey": "..."}} を伴う 202
  • ListKey のポーリング → 完了時に {"IdentifierList": {"CID": [...]}}

一般的なワークフロー

ワークフロー 1:医薬品パネル内でのプロパティ比較

目標:少数の小分子セットの物理化学的性質を並べて比較します。

import requests, pandas as pd, time
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

drugs = ["aspirin", "ibuprofen", "naproxen", "celecoxib"]

# Resolve names → CIDs in a loop (rate-limited)
cids = []
for d in drugs:
    cid = requests.get(f"{BASE}/compound/name/{quote(d)}/cids/JSON",
                       timeout=15).json()["IdentifierList"]["CID"][0]
    cids.append(cid)
    time.sleep(0.25)

# Single batched property pull
cid_csv = ",".join(str(c) for c in cids)
r = requests.get(
    f"{BASE}/compound/cid/{cid_csv}/property/"
    "MolecularWeight,XLogP,TPSA,HBondDonorCount,HBondAcceptorCount/JSON")
df = pd.DataFrame(r.json()["PropertyTable"]["Properties"])
df["Name"] = drugs
df = df[["Name", "CID", "MolecularWeight", "XLogP", "TPSA",
         "HBondDonorCount", "HBondAcceptorCount"]]
print(df.to_string(index=False))
ワークフロー 2:リード化合物 → 類似アナログ → プロパティ

目標:キナーゼ阻害剤(ゲフィチニブ)を起点に、85%類似するアナログを見つけ、そのプロパティを取得します。

import requests, time
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

def poll_listkey(listkey, max_polls=10, interval=2.0):
    for _ in range(max_polls):
        time.sleep(interval)
        j = requests.get(f"{BASE}/compound/listkey/{listkey}/cids/JSON",
                         timeout=20).json()
        if "IdentifierList" in j:
            return j["IdentifierList"]["CID"]
    raise TimeoutError("listkey timeout")

# 1. lead → CID → canonical SMILES
ref_cid = requests.get(
    f"{BASE}/compound/name/gefitinib/cids/JSON").json()["IdentifierList"]["CID"][0]
ref_smi = requests.get(
    f"{BASE}/compound/cid/{ref_cid}/property/SMILES/JSON"
    ).json()["PropertyTable"]["Properties"][0]["SMILES"]
print(f"gefitinib CID={ref_cid}  SMILES={ref_smi}")

# 2. similarity search
smi_q = quote(ref_smi, safe="")
init = requests.get(
    f"{BASE}/compound/similarity/smiles/{smi_q}/JSON?Threshold=85&MaxRecords=15"
    ).json()
sim_cids = poll_listkey(init["Waiting"]["ListKey"]) if "Waiting" in init \
           else init["IdentifierList"]["CID"]
print(f"  {len(sim_cids)} analogs @85% Tanimoto")

# 3. batch-pull properties for top 5 analogs
cid_csv = ",".join(str(c) for c in sim_cids[:5])
r = requests.get(
    f"{BASE}/compound/cid/{cid_csv}/property/"
    "MolecularWeight,XLogP,TPSA,RotatableBondCount/JSON")
for row in r.json()["PropertyTable"]["Properties"]:
    print(f"  CID {row['CID']}: MW={row['MolecularWeight']} XLogP={row['XLogP']}")
ワークフロー 3:部分構造によるファーマコフォアスクリーニング → 生物活性の確認

目標:スルホンアミドモチーフを持つ化合物を見つけ、生物活性の記録があるものを確認します。

import requests, time
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

def poll_listkey(listkey, max_polls=10, interval=2.0):
    for _ in range(max_polls):
        time.sleep(interval)
        j = requests.get(f"{BASE}/compound/listkey/{listkey}/cids/JSON",
                         timeout=20).json()
        if "IdentifierList" in j:
            return j["IdentifierList"]["CID"]
    raise TimeoutError("listkey timeout")

smi = quote("S(=O)(=O)N", safe="")
init = requests.get(
    f"{BASE}/compound/substructure/smiles/{smi}/JSON?MaxRecords=10").json()
cids = poll_listkey(init["Waiting"]["ListKey"]) if "Waiting" in init \
       else init["IdentifierList"]["CID"]
print(f"sulfonamide CIDs: {cids}")

# Bioactivity row counts for the first few hits
for cid in cids[:3]:
    rows = requests.get(f"{BASE}/compound/cid/{cid}/assaysummary/JSON",
                        timeout=30).json().get("Table", {}).get("Row", [])
    print(f"  CID {cid}: {len(rows)} assay rows")
    time.sleep(0.3)

主要なパラメーター

パラメーターエンドポイント/モジュールデフォルト範囲/オプション効果
<namespace>/compound/{ns}/<value>/...—name、cid、smiles、inchikey、inchi、formula入力識別子の種類
<property csv>/.../property/<csv>/JSON—任意のプロパティ名(表を参照)の組み合わせ返すプロパティ(リクエストごとに DB 呼び出し 1 回)
Thresholdsimilarity(M4)900~100Tanimoto カットオフ(パーセント)
MaxRecordssimilarity/substructure/formula(サーバー側のデフォルト)1~10000非同期結果リストの上限
image_size/compound/cid/{cid}/PNGmediumsmall、large、WxH(例:500x500)PNG 出力の解像度
record_type/compound/cid/{cid}/SDF2d2d、3dSDF の次元(?record_type=3d)
MaxAssayResults/compound/cid/{cid}/assaysummary/JSON—整数化合物に数千件のレコードがある場合のアッセイ行数の上限

ベストプラクティス

  1. 名前または外部識別子から開始する場合は、必ず最初に cids/JSON を使います。 名前から CID への解決と、CID からプロパティへの検索は別々の呼び出しです。name → property で一度に行うこともできますが、後続のクエリで必要となる正規の CID リストが失われます。

  2. プロパティはまとめて取得し、個別にループしないでください。 compound/cid/2244,3672,2157,.../property/MolecularWeight,XLogP,.../JSON は、最大約 200 個の CID と任意の数のプロパティを受け付けるため、N 回ではなく 1 回の往復で済みます。名前ごとに get_compounds をループして呼び出すのは、レート制限にかかる最もよくある原因です。

  3. すべての SMILES を URL エンコードしてください。 urllib.parse.quote(smiles, safe="") を使用します。=, #, (, ), [, ] を含むエンコード前の SMILES は動作することもありますが、+、/、\、またはクエリ文字列のような部分文字列が含まれると、予測不能な形で失敗します。

  4. 類似性/部分構造/分子式の検索は非同期として扱ってください。 "Waiting" in response を条件に分岐し、検索を再実行するのではなく listkey をポーリングします。検索を再実行すると新しい ListKey が作成され、サーバーのジョブ枠を無駄にします。

  5. リクエストは毎秒 5 件以下、毎分 400 件以下に制限してください。 連続ループには time.sleep(0.25) を挿入します。HTTP 503 は制限に達したことを意味します。10 秒待って、同時実行数を減らしてください。

  6. MolecularWeight は float にキャストしてください。 小数の精度を完全に保つため、文字列("180.16")として返されます。文字列を数値のしきい値と比較すると、気付かないままバグになります。

  7. CID が 100 件以上の場合は POST を使用してください。 約 2000 文字を超える GET URL は、一部の HTTP プロキシによって切り詰められます。PubChem は、フォーム本文に cid を含めた POST も受け付けます:requests.post(f"{BASE}/compound/cid/property/MolecularWeight/JSON", data={"cid": cid_csv})。

  8. 2025 年の SMILES プロパティ名の変更。 PubChem は、2025 年の PUG-REST スキーマで 2 つの SMILES プロパティの名前を変更しました。旧 IsomericSMILES(立体情報を含む)は SMILES に、旧 CanonicalSMILES(立体情報を含まない結合情報のみ)は ConnectivitySMILES になりました。URL パスでは引き続き旧名を入力として受け付けます(例:/property/CanonicalSMILES/JSON は 200 を返します)が、レスポンス JSON のキーには新しい名前が使われます。そのため、リクエストは成功しても、パース処理だけが KeyError で失敗します。新しいコードでは SMILES/ConnectivitySMILES を使用し、それらのキーを読み取ってください。

よく使うレシピ

レシピ 1 — リピンスキーの Rule of Five チェック
import requests
from urllib.parse import quote

BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"

def check_lipinski(name):
    cid = requests.get(f"{BASE}/compound/name/{quote(name)}/cids/JSON"
                       ).json()["IdentifierList"]["CID"][0]
    p = requests.get(
        f"{BASE}/compound/cid/{cid}/property/"
        "MolecularWeight,XLogP,HBondDonorCount,HBondAcceptorCount/JSON"
        ).json()["PropertyTable"]["Properties"][0]
    mw, xlogp = float(p["MolecularWeight"]), p.get("XLogP", 0) or 0
    hbd, hba  = p["HBondDonorCount"], p["HBondAcceptorCount"]
    rules = {"MW ≤ 500": mw <= 500, "XLogP ≤ 5": xlogp <= 5,
             "HBD ≤ 5": hbd <= 5,   "HBA ≤ 10": hba <= 10}
    v = sum(1 for ok in rules.values() if not ok)
    return rules, v

rules, v = check_lipinski("metformin")
print(f"violations: {v}/4 ({'PASS' if v <= 1 else 'FAIL'})")
for r, ok in rules.items(): print(f"  {'✓' if ok else '✗'} {r}")
レシピ 2 — すべての同義語/商品名を取得
import requests

r = requests.get("https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/aspirin/synonyms/JSON")
syns = r.json()["InformationList"]["Information"][0]["Synonym"]
print(f"{len(syns)} synonyms")
for s in syns[:10]:
    print(f"  {s}")
レシピ 3 — 構造 PNG のダウンロード
import requests

cid = 2519   # caffeine
png = requests.get(
    f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cid}/PNG?image_size=large"
    ).content
with open("caffeine.png", "wb") as f:
    f.write(png)
print(f"wrote caffeine.png ({len(png)} bytes)")
レシピ 4 — 再試行/429 ハンドリングを含む堅牢なセッション
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

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

r = s.get(
    "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/2244/property/MolecularWeight/JSON",
    timeout=15)
r.raise_for_status()
print(r.json()["PropertyTable"]["Properties"][0]["MolecularWeight"])

期待される出力

  • CID 検索(/.../cids/JSON):{"IdentifierList": {"CID": [...]}} — 整数 CID のリストです。名前検索では関連度順に並びます。
  • プロパティ(/.../property/.../JSON):{"PropertyTable": {"Properties": [{"CID": ..., "MolecularWeight": "180.16", ...}, ...]}}。入力順の CID ごとに 1 行です。MolecularWeight は文字列です。
  • 同義語:{"InformationList": {"Information": [{"CID": 2244, "Synonym": ["aspirin", "ACETYLSALICYLIC ACID", "50-78-2", ...]}]}}。
  • 非同期検索の開始:HTTP 202 と {"Waiting": {"ListKey": "12345..."}} が返されます。IdentifierList が返されるまで /compound/listkey/{key}/cids/JSON をポーリングします。
  • アッセイ概要:{"Table": {"Columns": {"Column": [...col names...]}, "Row": [{"Cell": [...]}, ...]}}。
  • SDF:CID ヘッダー行で始まるプレーンテキストです。M END の後に SDF プロパティブロックが続きます。
  • PNG:バイナリの image/png です。デフォルトサイズでは約 2~4 KB、image_size=large では約 10~20 KB です。

トラブルシューティング

問題原因解決方法
HTTP 404 PUGREST.NotFound名前/SMILES/分子式に一致するレコードがありませんCAS 番号または InChIKey を試してください。PubChem のウェブ UI でスペルを確認してください。RDKit の正準 SMILES は、入力 SMILES では解決できない場合でも解決できることがよくあります
類似性/部分構造検索の呼び出しで HTTP 202 が {"Waiting":...} のまま止まる非同期ジョブがまだ実行中です/compound/listkey/{key}/cids/JSON を 2 秒ごとに最大約 30 秒間ポーリングしてください。完了しない場合は MaxRecords を減らしてください
HTTP 503 PUGREST.ServerBusy1 秒あたり 5 リクエストまたは 1 分あたり 400 リクエストのレート制限に達しましたループに time.sleep(0.25) を挿入してください。レシピ 4 の Retry セッションを使用し、同時実行数を減らしてください
SMILES の URL で HTTP 400SMILES が URL エンコードされていませんurllib.parse.quote(smi, safe="") でラップしてください。#、+、/、\ はすべてパスの解析を妨げます
KeyError: 'CanonicalSMILES'/KeyError: 'IsomericSMILES'古い名前をリクエストしています。URL は 200 を返しますが、2025 年の JSON では ConnectivitySMILES/SMILES がキーになっていますp["ConnectivitySMILES"](立体情報なしの結合情報)または p["SMILES"](立体情報あり)を読み取ってください。プロパティ CSV を新しい名前に更新してください
TypeError: '>' not supported between instances of 'str' and 'int'MolecularWeight が文字列です算術比較を行う前に float(p["MolecularWeight"]) を実行してください
バッチ cid/2244,3672,... が一部の行しか返しませんURL がサーバーの制限を超えていますrequests.post(url, data={"cid": "2244,3672,..."}) に切り替えてください。値を除いた同じ URL を使い、本文に CSV を含めます
assaysummary テーブルが空ですCID にバイオアッセイのレコードがありませんすべての化合物がアッセイされているわけではありません。PubChem のウェブページで確認してください
有効な CID で XLogP が None ですその化合物のプロパティが計算されていません算術演算の前に p.get("XLogP", 0) or 0 で処理してください

関連スキル

  • chembl-database-bioactivity — IC50/Ki/Kd の標的結合データ。PubChem のアッセイ概要より詳細です
  • rdkit-cheminformatics — SMILES/MOL のローカル操作、フィンガープリント、記述子、骨格の抽出
  • pdb-database — PubChem CID で見つかった低分子と共結晶化したタンパク質構造

参考資料

コメント