| name | medical-device-registry-tracker |
| description | 医疗器械法规追踪 Skill。自动检索中国(NMPA/CMDE)、欧盟(EC/MDR/MDCG)、美国(FDA)、加拿大(Health Canada)等地区的医疗器械法规更新,生成汇总报告并上传到 IMA 知识库。每周五自动执行。
使用场景: - "帮我追踪本周医疗器械法规更新" - "生成最新的法规周报" - "查看本周FDA指南动态" - "追踪欧盟MDR指南更新" - 自动化:每周五 8:30 自动检索并上传到 IMA 知识库「MD法规更新汇总」
|
医疗器械法规追踪 Skill
概述
本 Skill 提供医疗器械法规动态追踪功能,覆盖以下地区和来源:
覆盖区域
| 区域 | 来源 | 说明 |
|---|
| 🇨🇳 中国 | NMPA、CMDE、中检院等 | 注册审批、指导原则、标准文件 |
| 🇪🇺 欧盟 | EC Health、Team NB、IMDRF | MDR、IVDR、MDCG指南、协调标准 |
| 🇺🇸 美国 | FDA CDRH | 指南文件、召回、安全警报 |
| 🇨🇦 加拿大 | Health Canada | 指南、最新消息 |
法规来源配置
所有来源配置存储在 config/sources.json,包含:
- URL 地址
- 页面类型(static/dynamic)
- 解析器选择
- 区域分类
核心流程
1. 日期范围计算
使用 date_utils.py 模块计算上周五到本周五的日期范围:
上周五 00:00:00 (北京时间) ~ 本周五 23:59:59 (北京时间)
主要函数:
get_week_date_range(): 获取本周期的起止日期
is_within_date_range(): 判断日期是否在范围内
parse_date(): 解析多种日期格式
2. 网页抓取方式
本 Skill 支持两种抓取方式,根据来源特性选择:
方式A:Web Fetch API(推荐,已验证)
直接使用 AI 工具抓取,无需脚本:
| 来源 | URL | 状态 |
|---|
| 🇪🇺 EU/EC | https://health.ec.europa.eu/medical-devices-sector/latest-updates_en | ✅ 成功 |
| 🇨🇦 Health Canada | https://www.canada.ca/en/health-canada/services/drugs-health-products/medical-devices/what-new.html | ✅ 成功 |
| 🌍 IMDRF | https://www.imdrf.org/documents | ✅ 成功 |
| 🇺🇸 FDA 召回 | https://www.fda.gov/medical-devices/medical-device-safety/medical-device-recalls | ✅ 成功 |
| 🇨🇳 CMDE | https://www.cmde.org.cn/ | ⚠️ 反爬虫保护 |
执行方式:
使用 web_fetch 工具直接抓取网页内容
方式B:Python 脚本
使用 parsers.py 模块抓取各来源网页:
from parsers import fetch_all_sources_with_webfetch_tracking, fetch_page
all_items, web_fetch_sources = fetch_all_sources_with_webfetch_tracking(
config, start_date, end_date
)
抓取策略:
type="static" → requests + BeautifulSoup(直接抓取)
type="dynamic" → Playwright(JS渲染页面)
type="web_fetch" → 生成待补抓清单,由 AI web_fetch 工具处理 ⚠️
- 脚本会在
scripts/reports/ 目录生成 web_fetch_pending_{start}_{end}.json
- AI 读取该文件,对每个 URL 执行 web_fetch 工具
- 将抓取结果保存为
web_fetch_supplement_{start}_{end}.json
- 然后重新运行
run_tracker.py --web-fetch-items <该json文件>
- 静态页面:使用
requests + BeautifulSoup
- 动态页面(JS渲染):使用
Playwright
- 请求间隔:1秒(礼貌性延迟)
- 超时:30秒
3. 内容解析
各来源使用专用解析器:
| 解析器 | 适用来源 |
|---|
parse_nmpa() | NMPA 药监局 |
parse_cmde() | CMDE 器械审评中心 |
parse_ec_health() | 欧盟 EC Health |
parse_fda() | FDA 相关页面 |
parse_ca_health() | Health Canada |
parse_imdrf() | IMDRF |
parse_teamnb() | Team NB |
解析字段:
title: 标题
url: 原文链接
source: 来源名称
publish_date: 发布日期
tags: 自动提取的标签(如「征求意见」「MDR」「FDA」等)
4. 去重机制
使用 deduplicator.py 模块管理本地去重记录:
from deduplicator import RegistryDeduplicator
dedup = RegistryDeduplicator()
if dedup.is_seen(url="...", title="...", source="中检院公告通知"):
print("已推送过,跳过")
new_items = dedup.filter_new(all_items)
dedup.add(url="...", title="...", source="...", region="CN")
去重策略(2026-04-24 修复):
- 使用「来源 + URL」和「来源 + 标准化标题」复合键去重
- 同一来源的相同 URL 或相同标题才视为重复
- 不同来源的相同 URL/标题互不影响
- 解决了 EU 来源 in-place 更新(URL 不变但内容/日期更新)被误拦的问题
- 存储位置:
data/seen_registry.json
5. 报告生成
使用 report_generator.py 模块生成 Markdown 报告:
from report_generator import ReportGenerator
gen = ReportGenerator(start_date, end_date)
gen.add_item("CN", {"title": "...", "source": "...", ...})
gen.add_item("EU", {...})
report_content = gen.generate()
gen.save(Path("output.md"))
报告格式(符合用户样例):
- 概览统计表:各区域新增数量
- 区域法规详情:按区域分类,每条包含标题、来源、日期、链接、摘要、合规影响
- 历史记录更新:本期新增条目汇总
- 抓取状态说明:各来源抓取状态
6. IMA 上传
使用 IMA OpenAPI 将报告作为笔记上传到知识库:
目标知识库:
- 名称:MD法规更新汇总
- ID(通过
get_addable_knowledge_base_list 获取):ihJNh4Nl87Wqv-XLfXyOJSW1NMOBnVnk-HBnlcYgL4o=
上传流程(两步,必须按顺序):
⚠️ IMA 有两套 API,切勿混淆:
- 笔记模块:
/openapi/note/v1/ — 管理笔记内容
- 知识库模块:
/openapi/wiki/v1/ — 管理知识库条目
Step 1 — 创建笔记(笔记模块):
POST https://ima.qq.com/openapi/note/v1/import_doc
Body: {"title": "标题", "content": "报告内容", "content_format": 1}
返回: {"code": 0, "data": {"note_id": "xxx"}}
注意:返回字段用 code=0(非 retcode=0),笔记 ID 在 data.note_id
Step 2 — 关联到知识库(知识库模块):
POST https://ima.qq.com/openapi/wiki/v1/add_knowledge
Body: {
"media_type": 11,
"note_info": {"content_id": "<note_id>"},
"title": "标题",
"knowledge_base_id": "ihJNh4Nl87Wqv-XLfXyOJSW1NMOBnVnk-HBnlcYgL4o="
}
返回: {"code": 0, "data": {"media_id": "xxx"}}
凭证配置:
mkdir -p ~/.config/ima
echo "your_client_id" > ~/.config/ima/client_id
echo "your_api_key" > ~/.config/ima/api_key
export IMA_OPENAPI_CLIENTID="your_client_id"
export IMA_OPENAPI_APIKEY="your_api_key"
⚠️ 凭证文件为 UTF-16 编码,Python 读取示例:
with open(path, "rb") as f:
raw = f.read()
for enc in ["utf-16", "utf-8", "gbk"]:
try: client_id = raw.decode(enc).strip(); break
except: continue
Python 上传脚本已集成在 scripts/ima_upload_report.py,可独立运行或通过 run_tracker.py 自动调用。
执行方式
手动执行
python scripts/run_tracker.py
python scripts/run_tracker.py --dry-run
python scripts/run_tracker.py --date 2026-04-10
自动化执行
通过 WorkBuddy 自动化配置每周五 8:30 执行:
触发时间: 每周五 08:30 (北京时间)
执行命令: python scripts/run_tracker.py
工作目录: ~/.workbuddy/skills/medical-device-registry-tracker
依赖要求
必需依赖
pip install requests beautifulsoup4
可选依赖(增强抓取能力)
pip install playwright
playwright install chromium
文件结构
medical-device-registry-tracker/
├── SKILL.md # Skill 定义
├── config/
│ └── sources.json # 法规来源配置
├── scripts/
│ ├── run_tracker.py # 主执行脚本
│ ├── date_utils.py # 日期工具
│ ├── deduplicator.py # 去重模块
│ ├── report_generator.py # 报告生成
│ └── parsers.py # 网页解析器
├── data/ # 数据存储
│ └── seen_registry.json # 已推送记录
└── reports/ # 生成的报告
注意事项
- 时区处理:所有日期计算基于北京时间 (UTC+8)
- 反爬策略:
- 使用真实 User-Agent
- 请求间隔 1 秒
- 失败自动重试
- IMA 凭证:首次使用需配置 API 凭证
- 去重安全:本地记录不会自动清理,可手动编辑
data/seen_registry.json
故障排查
抓取失败
python -c "import requests, bs4; print('OK')"
curl -I https://www.nmpa.gov.cn
python scripts/parsers.py
IMA 上传失败
cat ~/.config/ima/client_id
cat ~/.config/ima/api_key
curl -X POST https://ima.qq.com/openapi/note/v1/import_doc \
-H "ima-openapi-clientid: ..." \
-H "ima-openapi-apikey: ..." \
-H "Content-Type: application/json" \
-d '{"title":"test","content":"test","content_format":1}'
更新日志
- 2026-04-24(下午):
- IMA 上传流程修正:
- 知识库名称从占位符
MD 法规更新-Testing 更正为 MD法规更新汇总
- 补充正确的 KB ID:
ihJNh4Nl87Wqv-XLfXyOJSW1NMOBnVnk-HBnlcYgL4o=(通过 get_addable_knowledge_base_list 获取)
- 完整记录两步上传流程(笔记模块 → 知识库模块),包括返回格式说明(
code=0 而非 retcode=0)
- 补充凭证文件 UTF-16 编码读取方法
- 修正 curl 示例 URL(
/v1/ → /v1/,路径原已正确,补全 Content-Type header)
- 关联上传脚本:
scripts/ima_upload_report.py(Step 1 创建笔记 + Step 2 关联知识库)
- 2026-04-24:
- 去重逻辑重构(
deduplicator.py):
- 旧策略:
is_seen() 用 URL OR title 任一匹配即过滤
- 新策略:改为「来源 + URL」和「来源 + 标准化标题」复合键去重
- 解决了 EU 来源 in-place 更新被误拦的核心 bug
filter_new() 现在传入 source 参数,确保去重键正确构建
- EU 来源URL更新(
sources.json):
ec_guidance(MDCG指南):原URL已404,更新为 /medical-devices-sector-new-regulation/ 路径
- 新增4个EU来源(
sources.json,类型:web_fetch):
ec_emdn — EMDN欧洲医疗器械命名法官方页(含MDCG 2021-12 EMDN FAQ)
ec_mdr_revision — EU MDR/IVDR Targeted Revision提案页(COM/2025/800,170页改革)
ec_borderline — 边境分类手册(含数字健康产品边界判定,2026年更新)
ec_clinical_national — 成员国临床试验国家要求(2026年更新)
ec_mir_xsd — 制造商不良事件报告XSD/SB 11154(EUDAMED警戒模块)
- 新增2个US/CA来源(
sources.json):
fda_safety_comm — FDA医疗器械安全通讯(Safety Communications专用页面)
ca_announcements — Health Canada医疗器械专项公告页面
- 注:用户提供的FDA CDRH新闻链接已确认配置正确 ✅
- web_fetch_urls 更新:新增
new_eu_2026 和 new_us_ca_2026 列表
- web_fetch来源处理流程重构(
run_tracker.py + parsers.py):
- 根因:
fetch_source() 对 来源静默返回 ,导致FDA CDRH新闻等来源被漏抓(AI工具从未收到这些URL)