关于 fda-database
fda-database 是用于查询 openFDA 公共监管数据的技能,面向药物安全监测、标签检索和产品调查。它通过 REST API 提供 FAERS 不良事件、药品标签、NDC 产品及召回数据的搜索与聚合。
主要功能
- 01搜索 FAERS 药物不良事件报告
- 02按药物汇总常见不良事件
- 03检索药品标签及警告信息
- 04按 NDC 或成分查询药品产品
- 05查找药品召回和执法行动
适用场景
- 01比较同类药物的不良事件报告
- 02提取药品适应症、禁忌和警告
- 03核查药品召回及执法记录
- 04构建药物安全信号监测流程
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill fda-database安装后在 Claude Code 中输入/fda-database确认已加载。
详细介绍
openFDA 药品与不良事件数据库
概述
openFDA 通过简单的 REST API 提供 FDA 监管数据的公开访问。主要数据集包括 FDA 不良事件报告系统(FAERS),其中有 2,000 多万份不良事件报告;药品产品标签(NDC、SPL);药品批准信息(Drugs@FDA);医疗器械报告;以及召回执法行动。该 API 支持使用 Elasticsearch 风格语法进行全文搜索和结构化查询。
适用场景
- 检索某种药品的不良事件报告,以评估安全信号和副作用特征
- 查询 FAERS,进行不成比例分析(比较不同药品的不良事件特征)
- 按药品名称或 NDC 查找官方药品标签(适应症、禁忌症、警告、剂量)
- 按药品名称或公司搜索药品召回和执法行动
- 查找所有含有指定活性成分的上市产品
- 构建药物警戒工作流,通过公开监管数据监测药品安全信号
- 如需临床试验疗效数据,请使用
clinicaltrials-database-search;如需药品结构/靶点信息,请使用drugbank-database-access
前提条件
- Python 包:
requests、pandas - 数据要求:药品名称、活性成分、MedDRA 术语、NDC 代码
- 环境:需要互联网连接;基本使用无需身份验证
- 速率限制:不使用 API 密钥时每天 1000 次请求;使用 https://open.fda.gov/apis/authentication/ 提供的免费 API 密钥时每天 120,000 次请求
pip install requests pandas
快速开始
import requests
BASE = "https://api.fda.gov/drug"
# Optional: add api_key parameter for higher rate limits
# Find adverse events for aspirin
r = requests.get(
f"{BASE}/event.json",
params={
"search": 'patient.drug.medicinalproduct:"aspirin"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": 10
}
)
r.raise_for_status()
data = r.json()
print("Top adverse reactions for aspirin:")
for item in data["results"][:5]:
print(f" {item['term']:40s} count={item['count']}")
核心 API
查询 1:不良事件报告搜索(FAERS)
在 FDA 不良事件报告系统中搜索药品与事件的关联。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def faers_search(drug_name, limit=100):
"""Search FAERS for adverse event reports mentioning a drug."""
r = requests.get(f"{BASE}/event.json",
params={"search": f'patient.drug.medicinalproduct:"{drug_name}"',
"limit": limit})
r.raise_for_status()
return r.json()
data = faers_search("warfarin", limit=5)
total = data["meta"]["results"]["total"]
print(f"Total FAERS reports for warfarin: {total:,}")
# Show first report summary
report = data["results"][0]
print(f"\nReport {report['safetyreportid']}:")
print(f" Date : {report.get('receivedate', 'n/a')}")
print(f" Serious : {report.get('serious', 'n/a')}")
drugs = [d.get("medicinalproduct", "n/a") for d in report.get("patient", {}).get("drug", [])]
print(f" Drugs : {drugs[:5]}")
reactions = [r.get("reactionmeddrapt", "n/a") for r in report.get("patient", {}).get("reaction", [])]
print(f" Reactions: {reactions[:5]}")
查询 2:统计某种药品的高频不良事件
使用 count 参数汇总不良事件术语。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def top_adverse_events(drug_name, limit=20):
"""Get the most frequently reported adverse events for a drug."""
r = requests.get(f"{BASE}/event.json",
params={
"search": f'patient.drug.medicinalproduct:"{drug_name}"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": limit
})
r.raise_for_status()
results = r.json()["results"]
return pd.DataFrame(results).rename(columns={"term": "reaction", "count": "reports"})
df_atorvastatin = top_adverse_events("atorvastatin", limit=15)
print("Top adverse events for atorvastatin:")
print(df_atorvastatin.head(10).to_string(index=False))
df_atorvastatin.to_csv("atorvastatin_adverse_events.csv", index=False)
# Compare two drugs: adverse event profile overlap
df_drug1 = top_adverse_events("simvastatin", limit=20)
df_drug2 = top_adverse_events("atorvastatin", limit=20)
common = set(df_drug1["reaction"]) & set(df_drug2["reaction"])
print(f"\nCommon adverse events (simvastatin ∩ atorvastatin): {len(common)}")
print("Shared reactions:", list(common)[:10])
查询 3:药品标签搜索
检索官方药品标签(适应症、警告、剂量、禁忌症)。
import requests
BASE = "https://api.fda.gov/drug"
def get_label(drug_name):
"""Retrieve FDA drug label by brand or generic name."""
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.brand_name:"{drug_name}"',
"limit": 1})
if r.status_code == 404:
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.generic_name:"{drug_name}"',
"limit": 1})
r.raise_for_status()
results = r.json()["results"]
return results[0] if results else None
label = get_label("Lipitor")
if label:
print(f"Brand name : {label.get('openfda', {}).get('brand_name', ['n/a'])[0]}")
print(f"Generic name: {label.get('openfda', {}).get('generic_name', ['n/a'])[0]}")
print(f"Manufacturer: {label.get('openfda', {}).get('manufacturer_name', ['n/a'])[0]}")
indications = label.get("indications_and_usage", ["n/a"])[0]
print(f"\nIndications (first 300 chars):\n{indications[:300]}...")
查询 4:按 NDC 查询药品产品
按国家药品代码检索上市产品信息。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def ndc_search(ndc_or_name, limit=10):
"""Search NDC directory for drug product information."""
# Search by product name or NDC
r = requests.get(f"{BASE}/ndc.json",
params={"search": f'generic_name:"{ndc_or_name}"',
"limit": limit})
r.raise_for_status()
return r.json()
data = ndc_search("metformin", limit=10)
total = data["meta"]["results"]["total"]
print(f"Metformin products: {total}")
rows = []
for prod in data["results"]:
rows.append({
"product_ndc": prod.get("product_ndc"),
"brand_name": prod.get("brand_name"),
"generic_name": prod.get("generic_name"),
"dosage_form": prod.get("dosage_form"),
"route": ", ".join(prod.get("route", [])),
"labeler": prod.get("labeler_name"),
})
df = pd.DataFrame(rows)
print(df.to_string(index=False))
查询 5:药品召回搜索
按药品名称或公司搜索 FDA 执法行动和药品召回。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def drug_recalls(drug_name, limit=20):
"""Find FDA drug recalls for a given drug name."""
r = requests.get(f"{BASE}/enforcement.json",
params={
"search": f'product_description:"{drug_name}"',
"limit": limit
})
if r.status_code == 404:
return pd.DataFrame()
r.raise_for_status()
results = r.json()["results"]
return pd.DataFrame([{
"recalling_firm": rec.get("recalling_firm"),
"product": rec.get("product_description", "")[:80],
"reason": rec.get("reason_for_recall", "")[:100],
"classification": rec.get("classification"),
"recall_date": rec.get("recall_initiation_date"),
"status": rec.get("status"),
} for rec in results])
recalls = drug_recalls("metformin", limit=5)
print(f"Metformin recalls: {len(recalls)}")
if not recalls.empty:
print(recalls[["recalling_firm", "classification", "recall_date", "status"]].to_string(index=False))
查询 6:跨产品搜索活性成分
查找所有含有特定活性成分的药品产品。
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def products_by_ingredient(ingredient, limit=50):
"""Find all FDA-listed products with a given active ingredient."""
r = requests.get(f"{BASE}/ndc.json",
params={
"search": f'active_ingredients.name:"{ingredient}"',
"limit": limit
})
r.raise_for_status()
data = r.json()
print(f"Total products with {ingredient}: {data['meta']['results']['total']}")
rows = []
for prod in data["results"]:
for ai in prod.get("active_ingredients", []):
if ingredient.lower() in ai.get("name", "").lower():
rows.append({
"brand": prod.get("brand_name"),
"generic": prod.get("generic_name"),
"strength": ai.get("strength"),
"dosage_form": prod.get("dosage_form"),
"route": ", ".join(prod.get("route", [])),
})
return pd.DataFrame(rows)
df = products_by_ingredient("metformin hydrochloride")
print(df.drop_duplicates(subset=["generic", "strength", "dosage_form"]).head(10).to_string(index=False))
核心概念
openFDA API 端点
| 端点 | 数据集 | 主要用途 |
|---|---|---|
/drug/event.json | FAERS(不良事件) | 药物警戒、安全信号 |
/drug/label.json | 结构化产品标签 | 适应症、警告、剂量 |
/drug/ndc.json | NDC 目录 | 上市产品、规格 |
/drug/enforcement.json | 召回与执法 | 药品召回、市场撤回 |
/device/event.json | MAUDE(器械事件) | 医疗器械不良事件 |
查询语法
openFDA 使用 Elasticsearch 风格的查询。使用 field:"exact phrase" 进行精确匹配,使用 field:term 进行模糊匹配,使用 +field1:"A" +field2:"B" 表示 AND 逻辑。使用 count 参数进行汇总(相当于 GROUP BY)。使用 limit(1–1000)进行分页,并通过 skip 设置偏移量。
常见工作流
工作流 1:药品安全信号分析
目标:比较同一治疗类别中多种药品的不良事件频率,以识别差异化的安全特征。
import requests, pandas as pd, time
BASE = "https://api.fda.gov/drug"
drugs = ["atorvastatin", "simvastatin", "rosuvastatin"]
def count_reactions(drug, limit=20):
r = requests.get(f"{BASE}/event.json",
params={"search": f'patient.drug.medicinalproduct:"{drug}"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": limit})
if r.status_code != 200:
return pd.Series(dtype=float, name=drug)
df = pd.DataFrame(r.json()["results"])
df.columns = ["reaction", drug]
return df.set_index("reaction")[drug]
series_list = []
for drug in drugs:
s = count_reactions(drug, limit=20)
series_list.append(s)
time.sleep(0.5)
comparison = pd.concat(series_list, axis=1).fillna(0)
comparison = comparison.sort_values(drugs[0], ascending=False)
print("Adverse event count comparison (statins):")
print(comparison.head(10).to_string())
comparison.to_csv("statin_safety_comparison.csv")
工作流 2:药品标签信息提取器
目标:提取多种药品的适应症、禁忌症和警告,并保存为 CSV。
import requests, pandas as pd, time, re
BASE = "https://api.fda.gov/drug"
def get_label_sections(drug_name):
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.generic_name:"{drug_name}"', "limit": 1})
if r.status_code != 200 or not r.json()["results"]:
return None
label = r.json()["results"][0]
def clean(field):
text = " ".join(label.get(field, [""]))
return re.sub(r"\s+", " ", text).strip()[:500]
return {
"drug": drug_name,
"indications": clean("indications_and_usage"),
"contraindications": clean("contraindications"),
"warnings": clean("warnings_and_cautions") or clean("warnings"),
}
drugs = ["metformin", "atorvastatin", "lisinopril", "omeprazole"]
rows = []
for drug in drugs:
info = get_label_sections(drug)
if info:
rows.append(info)
time.sleep(0.4)
df = pd.DataFrame(rows)
df.to_csv("drug_labels.csv", index=False)
print(df[["drug", "indications"]].to_string(index=False))
关键参数
| 参数 | 模块 | 默认值 | 范围 / 选项 | 作用 |
|---|---|---|---|---|
search | 所有端点 | — | Elasticsearch 语法 | 筛选查询 |
count | 所有端点 | — | 字段名称 + .exact | 按字段值聚合/计数 |
limit | 所有端点 | 1 | 1–1000 | 每次请求的结果数 |
skip | 所有端点 | 0 | 整数 | 分页偏移量 |
api_key | 所有端点 | — | API 密钥字符串 | 将速率限制提高到每天 120K 次 |
.exact 后缀 | count 字段 | — | 附加在字段名称后 | 精确字符串匹配,而非分词匹配 |
最佳实践
-
获取免费 API 密钥:在 https://open.fda.gov/apis/authentication/ 注册即可立即获取密钥,并将每日请求限额从 1,000 次提高到 120,000 次;生产环境中必不可少。
-
搜索药品名称时使用
.exact:patient.drug.medicinalproduct.exact(而不是.medicinalproduct)可进行精确短语匹配,避免部分匹配导致计数虚高。 -
规范化药品名称:FAERS 报告者使用多种名称拼写(例如,“Lipitor”、“atorvastatin calcium”、“ATORVASTATIN”)。可搜索多个名称变体,或使用通用成分字段以确保覆盖一致。
-
谨慎解读 FAERS 计数:报告数量不等于发生率。FAERS 为自愿报告,且存在报告偏倚;计数较高可能反映市场规模或媒体关注度,而非风险更高。
-
对大型结果集分页:
limit最大值为 1000;使用skip对大型结果集分页(meta.results中的total)。
常见示例
示例:统计某种药物的 FAERS 报告总数
适用场景:快速查看某种药物的不良事件报告总量。
import requests
drug = "ibuprofen"
r = requests.get("https://api.fda.gov/drug/event.json",
params={"search": f'patient.drug.medicinalproduct.exact:"{drug}"',
"limit": 1})
total = r.json()["meta"]["results"]["total"]
print(f"Total FAERS reports for {drug}: {total:,}")
示例:仅查找严重不良事件
适用场景:筛选 FAERS 中被归类为严重事件(死亡、住院、残疾)的报告。
import requests, pandas as pd
r = requests.get("https://api.fda.gov/drug/event.json",
params={
"search": 'patient.drug.medicinalproduct:"warfarin" AND serious:1',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": 10
})
df = pd.DataFrame(r.json()["results"])
df.columns = ["reaction", "serious_reports"]
print(df.to_string(index=False))
示例:查询药品的上市批准状态
适用场景:确认药品是否获得 FDA NDA/ANDA 批准,并查找批准年份。
import requests
r = requests.get("https://api.fda.gov/drug/label.json",
params={"search": 'openfda.generic_name:"metformin"', "limit": 1})
label = r.json()["results"][0]
openfda = label.get("openfda", {})
print(f"Application numbers: {openfda.get('application_number', ['n/a'])}")
print(f"Product type: {openfda.get('product_type', ['n/a'])}")
print(f"NDA sponsor: {openfda.get('manufacturer_name', ['n/a'])}")
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
HTTP 404,并返回 {"error": {"code": "NOT_FOUND"}} | 查询无匹配结果 | 检查药品名称拼写;尝试其他名称格式 |
HTTP 429 Too Many Requests | 超出速率限制 | 注册获取 API 密钥;在请求之间添加 time.sleep(1) |
| 计数结果与预期不符 | 药品名称分词 | 使用 .exact 后缀:medicinalproduct.exact,而非 medicinalproduct |
| 标签搜索返回错误药品 | 名称存在歧义 | 添加 +openfda.product_type:"HUMAN PRESCRIPTION DRUG" 进行筛选 |
| FAERS 报告中缺少字段 | 自愿报告信息不完整 | 使用 .get("field", "n/a") 检查字段是否存在 |
出现 skip + limit > 26000 错误 | 分页限制 | openFDA 将分页上限设为 26,000 条记录;如需获取更多记录的聚合结果,请使用 count 端点 |
相关技能
clinicaltrials-database-search— 查询通过 openFDA 识别的药品临床试验数据drugbank-database-access— 药物结构、靶点和相互作用,用于辅助理解 FDA 数据chembl-database-bioactivity— FAERS 数据库中药品的临床前生物活性数据string-database-ppi— 通过不良事件分析发现的药物靶点的蛋白质相互作用
参考资料
- openFDA API 文档 — 完整的 API 参考、端点和查询语法
- openFDA API 密钥注册 — 免费注册以提高速率限制
- FAERS 概述 — 了解 FAERS 数据及其局限性
- openFDA GitHub — 源代码和数据下载参考