2026山东大学软件学院创新实训——IntelliHealth(六):个人总结:家庭药物管理模块链路打通
·
一、流程设计
起初,我想直接扫码后接入大模型接口,我想:
“既然有大模型,我能不能扫完条码直接问大模型,不建药品库了?”
答案是:
可以,但不能完全依赖大模型。
为什么不能完全依赖大模型?
假设用户扫到:
6907992101234
然后发给 Qwen:
这是一个药品条码:
6907992101234
请返回药品名称、成分、保质期、用法用量、副作用。
问题来了:
Qwen根本不知道这个条码是什么
因为:
- 大模型不是实时联网数据库
- 条码不是公开知识
- 绝大多数药品条码没有进入训练数据
结果是:

因此我只能换个思路,将流程换成:
ML Kit扫码
↓
得到条码
↓
第三方条码API
↓
药品名称
接入条形码API,得到药品名称。但此时还无法得到药品详细数据。
例如(仅供举例):
6907992101234
返回:
布洛芬缓释胶囊
然后:
MongoDB
drug_info
查询:
findByName("布洛芬缓释胶囊")
如果存在:
返回药品信息
如果不存在:
请求扫描说明书
↓
OCR
↓
Qwen
↓
写入drug_info
我最后放弃了:
条码
↓
直接得到成分
直接得到副作用
直接得到保质期
因为没找到稳定免费的药品条码数据库能保证这些字段。实际上很多商业APP也是:
条码
↓
得到药名
↓
查自己的药品库
最后我的设计:
扫码
↓
第三方条码API
得到:
药品名称
↓
MongoDB
有药品
↓
直接返回
没药品
↓
OCR说明书
↓
Qwen提取
↓
存MongoDB
下面是爬取数据的过程:
一、起点:从一个药品页面开始
最初的目标很简单:拿到一个药品的说明书数据。
以 39 药品通为例:
https://ypk.39.net/572623/manual/
页面结构非常清晰:
【药品名称】【成份】【适应症】【用法用量】【不良反应】
第一版解析代码(核心结构)
items = soup.select("ul.drug-explain li")
for item in items:
title = item.select_one(".drug-explain-tit")
content = item.select_one(".drug-explain-txt")
if title and content:
key = title.get_text(strip=True)
value = content.get_text(separator=" ", strip=True)
drug_info[key] = value
这一阶段我解决了两个问题:
- HTML结构解析(BeautifulSoup选择器)
- 数据结构标准化(dict存储)
输出结果已经是结构化 JSON,而不是 HTML
二、关键转折:从“单页爬虫”到“搜索系统”
真正的难点不是解析,而是:
❓ 如何找到所有药品?
我尝试了一个错误入口:
https://ypk.39.net/weishoulu_p1
结果返回:
未收录信息
这一步让我意识到:
很多网页“存在URL ≠ 有数据结构”
正确方式:搜索页提取药品列表
通过搜索接口:
https://ypk.39.net/search/布洛芬-NULL-b0-ci0-c0-m0-bm0-otc0-fd0-p0
解析结果:
for a in soup.find_all("a"):
text = a.get_text(strip=True)
href = a.get("href")
if "布洛芬" in text and href:
print(text, href)
这一阶段的突破:
✔ 从“单页面解析” → “搜索结果发现系统”
✔ 能获取多个药品条目
✔ 拿到了关键ID(药品详情页入口)
三、核心升级:构建“药品数据管道”
当我拿到药品列表后,系统开始具备“数据流”结构:
关键词 → 搜索页 → 药品列表 → 详情页 → 说明书 → 结构化数据
提取药品详情页
drug_urls = set()
for a in soup.find_all("a"):
text = a.get_text(strip=True)
href = a.get("href")
if "布洛芬" in text and "ypk.39.net" in href:
drug_urls.add(href)
拼接说明书页(关键设计)
def get_manual_url(drug_url):
return drug_url.rstrip("/") + "/manual/"
这里是整个系统的“数据扩展点”
四、系统化封装:模块化爬虫设计
当逻辑变复杂后,我把系统拆成三个模块:
1. 搜索模块
def search_drugs(keyword):
url = f"https://ypk.39.net/search/{keyword}-NULL-b0-ci0-c0-m0-bm0-otc0-fd0-p0"
2. 解析模块
def parse_manual(url):
soup = BeautifulSoup(requests.get(url).text, "html.parser")
data = {}
for item in soup.select("ul.drug-explain li"):
title = item.select_one(".drug-explain-tit")
content = item.select_one(".drug-explain-txt")
if title and content:
data[title.text.strip()] = content.text.strip()
return data
3. 数据流主控
for url in drug_urls:
manual_url = url.rstrip("/") + "/manual/"
data = parse_manual(manual_url)
五、从单药到批量系统(真正的转折)
当我把 keyword 写死时,系统是这样的:
keyword = "布洛芬"
但当我升级为文件输入后:
def load_keywords():
with open("keywords.txt", encoding="utf-8") as f:
return [line.strip() for line in f if line.strip()]
系统直接升级为:
多药品批量爬取系统
批量运行结构
for keyword in keywords:
drug_urls = search_drugs(keyword)
for url in drug_urls:
data = parse_manual(get_manual_url(url))
六、数据落地:CSV结构化存储
最终我选择 CSV 作为第一阶段存储方案:
df = pd.DataFrame(all_data)
df.to_csv("drug_data.csv", index=False, encoding="utf-8-sig")
数据成果:
| 药品名称 | 成份 | 适应症 | 用法用量 | 来源关键词 |
|---|
七、这次项目让我真正理解的3件事
1.爬虫不是“抓网页”,而是构建数据流
从:
HTML → dict → CSV → 数据库
本质是 ETL 流程。
2.网页结构 ≠ 数据结构
例如:
weishoulu_p1 ❌(假入口)
search页面 ✔
manual页面 ✔
学会判断“可用数据入口”比写代码更重要
小系统也有架构设计
我的最终结构变成:
search()
↓
get_urls()
↓
parse_manual()
↓
store_csv()
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)