news 2026/9/24 7:50:04

医疗数据采集怕踩红线?Python合规抓取公开病历与疾病趋势分析全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
医疗数据采集怕踩红线?Python合规抓取公开病历与疾病趋势分析全流程

做医疗相关数据分析或者公共卫生研究的朋友,应该都遇到过数据难题:想做疾病趋势分析,却不知道哪些数据能合法采集,要么找不到公开数据源,要么怕一不小心触碰患者隐私红线。网上很多教程一上来就教爬医院系统,殊不知很多操作已经踩了合规的红线,甚至涉嫌违法。

前段时间帮朋友做一组公开疾病数据的趋势分析,从数据源筛选、合规采集、文本清洗结构化,到最后的趋势分析与可视化,完整走了一遍流程。全程只采集完全公开的匿名聚合数据,不碰任何个人隐私信息,最终出来的分析结果完全能满足常规研究需求。

今天就把完整的实现思路、核心代码和合规注意事项全部分享出来,全程合法合规,新手也能照着复现。

一、先划红线:医疗数据采集的合规边界与数据源选择

做医疗数据采集,合规永远是第一位的,比技术实现重要一百倍。一旦触碰了个人隐私数据,后果不堪设想。先把不能碰的红线划清楚:

  1. 绝对不能爬取医院内部系统、非公开的电子病历系统,哪怕有可访问账号也不行
  2. 绝对不能采集包含患者姓名、身份证号、联系方式、具体就诊记录等可识别个人身份的信息
  3. 不能突破网站的授权机制,爬取需要权限才能查看的非公开数据
  4. 不能对采集到的数据进行二次传播、商用,要严格遵守数据使用协议

合规可采集的公开医疗数据

不是所有医疗数据都不能碰,以下几类公开数据是可以合规采集的:

  • 各级卫健委、疾控局官方发布的公开疾病监测数据、统计报表
  • 公立医疗机构公开的年度医疗质量报告、疾病科普与汇总数据
  • 公开医学期刊、学术平台发布的匿名化病例汇总数据
  • 国家公共卫生科学数据中心等官方平台开放的共享数据集
  • 法定公开的传染病疫情通报、公共卫生事件数据

这些数据都是经过匿名化、聚合处理的公开信息,采集时遵守网站robots协议和使用规定,控制请求频率,就完全合规。

技术选型

为什么选这套轻量方案,而不是更复杂的技术栈:

  • 采集层:官方公开站点大多是传统服务端渲染页面,没有复杂的前端反爬,requests+BeautifulSoup完全够用,轻量高效
  • 处理层:医疗文本结构化用正则+自定义医疗词典,配合pandas做数据处理,比通用大模型更可控,准确率也能满足需求
  • 分析层:pandas做统计聚合、时间序列分析,搭配matplotlib做可视化,本地就能跑,无需额外部署
  • 合规性:全程只处理公开聚合数据,不涉及任何个人隐私识别

整体处理流程:

二、分步实操:从采集到分析的完整实现

2.1 公开数据采集:以官方疾病监测数据为例

这里以某地方卫健委公开的月度疾病监测数据为例,这类数据通常以表格形式分页展示,没有复杂反爬,重点是控制频率,规范采集。

核心思路:先获取列表页,解析每条数据的详情链接,再逐个采集详情页的内容,最后汇总成结构化表。注意不要开高并发,单线程加间隔,避免给服务器造成压力。

核心代码片段:

import requests from bs4 import BeautifulSoup import pandas as pd import time session = requests.Session() session.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Referer": "[http://wjw.xxx.gov.cn/disease/list/](http://wjw.xxx.gov.cn/disease/list/)" }) disease_list = [] total_page = 12 # 公开数据总页数 for page in range(1, total_page + 1): url = f"[http://wjw.xxx.gov.cn/disease/list/index_{page}.html](http://wjw.xxx.gov.cn/disease/list/index_{page}.html)" resp = session.get(url, timeout=10) resp.encoding = "utf-8" soup = BeautifulSoup(resp.text, "html.parser") # 解析列表中的每条数据 items = soup.find_all("div", class_="list-item") for item in items: title = item.find("a").text.strip() detail_url = item.find("a")["href"] publish_date = item.find("span", class_="date").text.strip() # 只采集月度疾病监测通报 if "月度疾病监测" in title: disease_list.append({ "title": title, "detail_url": detail_url, "publish_date": publish_date }) print(f"第{page}页采集完成,当前累计{len(disease_list)}条") time.sleep(1.5) # 控制请求频率,避免给服务器造成压力 # 采集详情页数据 detail_data = [] for idx, item in enumerate(disease_list): resp = session.get(item["detail_url"], timeout=10) resp.encoding = "utf-8" soup = BeautifulSoup(resp.text, "html.parser") content = soup.find("div", class_="content").text.strip() detail_data.append({ "month": item["title"], "publish_date": item["publish_date"], "content": content }) time.sleep(1) if idx % 10 == 0: print(f"详情页采集进度:{idx+1}/{len(disease_list)}") # 保存原始数据 df = pd.DataFrame(detail_data) df.to_csv("disease_raw.csv", index=False, encoding="utf-8-sig") print(f"采集完成,共获取{len(df)}份月度监测数据")

几个关键的合规细节:

  • 严格控制请求频率,每页间隔1秒以上,绝不使用多并发轰炸官方站点
  • 只采集公开可访问的页面,不尝试绕过登录、不破解权限
  • 采集的数据仅用于研究分析,不二次传播、不商用

2.2 医疗文本清洗与实体结构化提取

采集下来的原始数据大多是自然语言文本,比如“本月报告甲类传染病2例,乙类传染病1256例,其中病毒性肝炎320例,肺结核280例…”,需要从中提取出疾病名称、病例数、时间这些结构化字段。

通用的NLP模型对医疗术语的识别准确率很低,这里不用复杂模型,用正则匹配+自定义疾病词典的方案,准确率高,可控性强,完全能处理标准化的公开报告。

第一步先构建自定义疾病词典,把常见的传染病、慢性病名称整理进去:

# 自定义疾病词典(示例,可根据需求扩展) DISEASE_DICT = [ "病毒性肝炎", "肺结核", "梅毒", "淋病", "细菌性痢疾", "流行性感冒", "手足口病", "水痘", "麻疹", "风疹", "高血压", "糖尿病", "冠心病", "脑梗死", "恶性肿瘤" ]

然后写提取函数,从文本中匹配疾病名称和对应的病例数:

import re import pandas as pd df = pd.read_csv("disease_raw.csv") def extract_disease_data(text, month): """从监测文本中提取疾病名称和病例数""" results = [] # 预处理:去掉多余空格和换行 text = re.sub(r'\s+', ' ', text) for disease in DISEASE_DICT: # 匹配模式:疾病名称 + 数字 + 例 pattern = re.compile(f'{disease}[^0-9]*(\d+)[^0-9]*例') match = pattern.search(text) if match: count = int(match.group(1)) results.append({ "month": month, "disease": disease, "case_count": count }) return results # 批量提取所有月份的数据 all_data = [] for _, row in df.iterrows(): month_data = extract_disease_data(row["content"], row["month"]) all_data.extend(month_data) # 转成DataFrame structured_df = pd.DataFrame(all_data) # 数据校验:剔除异常值 structured_df = structured_df[structured_df["case_count"] > 0] structured_df = structured_df[structured_df["case_count"] < 100000] # 合理范围校验 structured_df.to_csv("disease_structured.csv", index=False, encoding="utf-8-sig") print(f"结构化完成,共提取{len(structured_df)}条疾病数据")

补充说明:

  • 真实场景的文本格式会更多样,需要根据实际报告的格式调整正则规则
  • 可以加入同义词映射,比如“乙肝”对应“病毒性肝炎乙型”,提高召回率
  • 提取完一定要做数据校验,剔除明显不符合常理的异常值,避免影响分析结果

2.3 疾病趋势统计分析与可视化

数据结构化之后,就可以做多维度的趋势分析了。常规的分析维度包括:时间维度的发病趋势、疾病类型的占比分布、季节性特征分析、同比环比变化等。

这里做两个最常用的分析:月度发病趋势变化、疾病类型占比分析。

核心代码片段:

import pandas as pd import matplotlib.pyplot as plt import matplotlib # 设置中文显示 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] matplotlib.rcParams['axes.unicode_minus'] = False df = pd.read_csv("disease_structured.csv") # 1. 月度总发病数趋势 monthly_total = df.groupby("month")["case_count"].sum().reset_index() plt.figure(figsize=(12, 6)) plt.plot(monthly_total["month"], monthly_total["case_count"], marker='o', linewidth=2, color='#1f77b4') plt.title("月度法定传染病发病数趋势", fontsize=14) plt.xlabel("月份", fontsize=12) plt.ylabel("发病数(例)", fontsize=12) plt.xticks(rotation=45) plt.grid(alpha=0.3) plt.tight_layout() plt.savefig("monthly_trend.png", dpi=300) plt.close() # 2. 疾病类型占比(全年汇总) disease_total = df.groupby("disease")["case_count"].sum().reset_index() disease_total = disease_total.sort_values("case_count", ascending=False).head(10) plt.figure(figsize=(10, 6)) plt.bar(disease_total["disease"], disease_total["case_count"], color='#2ca02c') plt.title("全年各类疾病发病数TOP10", fontsize=14) plt.xlabel("疾病类型", fontsize=12) plt.ylabel("发病数(例)", fontsize=12) plt.xticks(rotation=45) plt.tight_layout() plt.savefig("disease_rank.png", dpi=300) plt.close() # 3. 计算同比环比 monthly_total["month_num"] = range(1, len(monthly_total)+1) monthly_total["mom"] = monthly_total["case_count"].pct_change() * 100 # 环比 monthly_total["yoy"] = monthly_total["case_count"].pct_change(12) * 100 # 同比 print("月度发病数同比环比:") print(monthly_total[["month", "case_count", "mom", "yoy"]].tail(6))

这样就能得到直观的趋势图表和统计数据,满足常规的公共卫生研究、数据分析需求。如果需要更深入的分析,还可以加入地区维度、人群维度的交叉分析。

三、踩坑实录:医疗数据采集分析最容易踩的5个坑

这套流程跑下来,踩了不少和医疗数据特性相关的坑,很多都是做普通数据采集碰不到的,整理出来帮大家避坑。

3.1 合规红线坑:别拿隐私数据开玩笑

这是最重要的一条。很多人觉得反正数据在网页上就能看到,爬下来也没事。实际上只要包含可识别的个人信息,哪怕是公开在医院网站上的,批量采集也可能涉嫌侵犯个人信息。
记住一个原则:只采集聚合的、匿名的、统计类的数据,不碰任何具体的个人就诊记录。哪怕是公开的病例,也要确认是完全匿名化、无法定位到个人的。

3.2 数据口径不一致坑:直接对比等于白分析

不同地区、不同年份的疾病统计口径很可能不一样,比如有的地方把疑似病例算进去,有的只算确诊;有的月份调整了统计范围。如果不看说明直接拉过来就对比,分析出来的趋势完全是错的。
采集的时候一定要把每个报告的统计说明、口径注释一起保存下来,分析前先对齐口径,不一致的数据不能放在一起比。

3.3 医疗实体识别坑:通用NLP根本不好用

最开始图省事,用通用的分词工具做实体提取,结果疾病名称识别错漏百出,把“病毒性肝炎”拆成“病毒”“性”“肝炎”,根本没法用。
医疗领域有大量专业术语,通用模型没有经过专项训练,准确率极低。不要迷信大模型,小批量标准化的数据,用自定义词典+正则的方案,准确率更高,还更可控。

3.4 数据失真坑:公开数据也会“改数”

官方公开的监测数据有时候会有修正,比如本月发布的数据,下个月可能会订正。如果采集完就不管了,后面数据更新了你也不知道,分析结果就会有偏差。
建议定期增量更新数据,同时保留历史版本,标注数据的采集时间和发布版本,出现差异的时候可以追溯。

3.5 采集频率坑:别给官方服务器添乱

医疗相关的官方站点,服务器资源大多优先保障业务使用,尤其是疾控、卫健委的网站,遇到公共卫生事件的时候访问量本来就大。这时候开多线程高并发去爬,不仅不道德,还很容易被封IP,甚至可能承担相应责任。
单线程+1秒以上间隔是基本操作,数据量不大的话慢一点也没关系,合规稳定最重要。

四、总结

医疗数据采集分析,技术从来都不是最大的难点,合规才是。很多人一上来就研究怎么爬医院系统、怎么搞病历数据,方向从一开始就错了。实际上公开的官方统计数据、学术共享数据,已经足够满足绝大多数研究和学习需求。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 7:36:48

STM32F407 USB Host直连4G模块:从硬件设计到AT指令状态机实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 7:35:51

ThinkPad UltraNav驱动v31.21.43.4安装与冲突排查:解决外接鼠标失灵

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 7:14:39

Flutter在HarmonyOS 6.0上构建录音控制区域:从权限到波形渲染全实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 7:12:16

无感FOC角度抖动终结者:PLL锁相环替代滑膜观测器实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华