KG-构建:知识图谱基础代码构建(医疗向)

news2025/7/2 6:41:47

项目来源是GitHub上面刘老师做的一个基于知识医疗图谱的问答机器人,本文主要关注点放在建立知识图谱这一侧。这个项目并且将数据集也开源了放在dict和data文件夹下,让我觉得真的很难得,得给老师一个star!

https://github.com/liuhuanyong/QASystemOnMedicalKG

data_spider.py

首先是数据获取阶段,解读刘老师的爬虫项目。 

import urllib.request
import urllib.parse
from lxml import etree
import pymongo
import re
 
 
class CrimeSpider:
    def __init__(self):
        self.conn = pymongo.MongoClient()
        self.db = self.conn['medical']
        self.col = self.db['data']
 
    '''根据url,请求html'''
    def get_html(self, url):
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                                 'Chrome/51.0.2704.63 Safari/537.36'}
        req = urllib.request.Request(url=url, headers=headers)
        res = urllib.request.urlopen(req)
        html = res.read().decode('gbk')
        return html
 
    '''url解析'''
    def url_parser(self, content):
        selector = etree.HTML(content)
        urls = ['http://www.anliguan.com' + i for i in  selector.xpath('//h2[@class="item-title"]/a/@href')]
        return urls
 
    '''测试'''
    def spider_main(self):
        for page in range(1, 11000):
            try:
                basic_url = 'http://jib.xywy.com/il_sii/gaishu/%s.htm'%page
                cause_url = 'http://jib.xywy.com/il_sii/cause/%s.htm'%page
                prevent_url = 'http://jib.xywy.com/il_sii/prevent/%s.htm'%page
                symptom_url = 'http://jib.xywy.com/il_sii/symptom/%s.htm'%page
                inspect_url = 'http://jib.xywy.com/il_sii/inspect/%s.htm'%page
                treat_url = 'http://jib.xywy.com/il_sii/treat/%s.htm'%page
                food_url = 'http://jib.xywy.com/il_sii/food/%s.htm'%page
                drug_url = 'http://jib.xywy.com/il_sii/drug/%s.htm'%page
                data = {}
                data['url'] = basic_url
                data['basic_info'] = self.basicinfo_spider(basic_url)
                data['cause_info'] =  self.common_spider(cause_url)
                data['prevent_info'] =  self.common_spider(prevent_url)
                data['symptom_info'] = self.symptom_spider(symptom_url)
                data['inspect_info'] = self.inspect_spider(inspect_url)
                data['treat_info'] = self.treat_spider(treat_url)
                data['food_info'] = self.food_spider(food_url)
                data['drug_info'] = self.drug_spider(drug_url)
                print(page, basic_url)
                self.col.insert(data)
 
            except Exception as e:
                print(e, page)
        return
 
    '''基本信息解析'''
    def basicinfo_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        title = selector.xpath('//title/text()')[0]
        category = selector.xpath('//div[@class="wrap mt10 nav-bar"]/a/text()')
        desc = selector.xpath('//div[@class="jib-articl-con jib-lh-articl"]/p/text()')
        ps = selector.xpath('//div[@class="mt20 articl-know"]/p')
        infobox = []
        for p in ps:
            info = p.xpath('string(.)').replace('\r','').replace('\n','').replace('\xa0', '').replace('   ', '').replace('\t','')
            infobox.append(info)
        basic_data = {}
        basic_data['category'] = category
        basic_data['name'] = title.split('的简介')[0]
        basic_data['desc'] = desc
        basic_data['attributes'] = infobox
        return basic_data
 
    '''treat_infobox治疗解析'''
    def treat_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        ps = selector.xpath('//div[starts-with(@class,"mt20 articl-know")]/p')
        infobox = []
        for p in ps:
            info = p.xpath('string(.)').replace('\r','').replace('\n','').replace('\xa0', '').replace('   ', '').replace('\t','')
            infobox.append(info)
        return infobox
 
    '''treat_infobox治疗解析'''
    def drug_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        drugs = [i.replace('\n','').replace('\t', '').replace(' ','') for i in selector.xpath('//div[@class="fl drug-pic-rec mr30"]/p/a/text()')]
        return drugs
 
    '''food治疗解析'''
    def food_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        divs = selector.xpath('//div[@class="diet-img clearfix mt20"]')
        try:
            food_data = {}
            food_data['good'] = divs[0].xpath('./div/p/text()')
            food_data['bad'] = divs[1].xpath('./div/p/text()')
            food_data['recommand'] = divs[2].xpath('./div/p/text()')
        except:
            return {}
 
        return food_data
 
    '''症状信息解析'''
    def symptom_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        symptoms = selector.xpath('//a[@class="gre" ]/text()')
        ps = selector.xpath('//p')
        detail = []
        for p in ps:
            info = p.xpath('string(.)').replace('\r','').replace('\n','').replace('\xa0', '').replace('   ', '').replace('\t','')
            detail.append(info)
        symptoms_data = {}
        symptoms_data['symptoms'] = symptoms
        symptoms_data['symptoms_detail'] = detail
        return symptoms, detail
 
    '''检查信息解析'''
    def inspect_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        inspects  = selector.xpath('//li[@class="check-item"]/a/@href')
        return inspects
 
    '''通用解析模块'''
    def common_spider(self, url):
        html = self.get_html(url)
        selector = etree.HTML(html)
        ps = selector.xpath('//p')
        infobox = []
        for p in ps:
            info = p.xpath('string(.)').replace('\r', '').replace('\n', '').replace('\xa0', '').replace('   ','').replace('\t', '')
            if info:
                infobox.append(info)
        return '\n'.join(infobox)
    '''检查项抓取模块'''
    def inspect_crawl(self):
        for page in range(1, 3685):
            try:
                url = 'http://jck.xywy.com/jc_%s.html'%page
                html = self.get_html(url)
                data = {}
                data['url']= url
                data['html'] = html
                self.db['jc'].insert(data)
                print(url)
            except Exception as e:
                print(e)
 
 
handler = CrimeSpider()
handler.inspect_crawl()

在这请忽略类的名称叫CrimeSpider,这是因为刘老师之前还做了一个完整的和司法案件有关的知识图谱,加上爬虫之间大同小异,改一改就能爬取另外一个网站。对于该爬虫文件我不做过多解读,详细情况可以参照本人另一篇博客。

https://blog.csdn.net/chen_nnn/article/details/122979611

这里我们主要关注一下,刘老师爬取的网站的情况,从代码中可以看出数据的原网站是寻医问药网的疾病百科。

 可以看到该网站的疾病百科从HTML的角度来看,结构较为清晰,比较适合爬取,之后的数据处理的工作量可以大大减少。爬虫将所有与该疾病相关的信息都进行爬取和存储,最终一共爬取了8807条和疾病有关的数据,里面的数据存储的结构如下。

build_data.py

该文件是将爬虫爬取到的数据进行规整,实现上图所示的结构。

MedicalGraph类:

import pymongo
from lxml import etree
import os
from max_cut import *
 
class MedicalGraph:
    def __init__(self):
        self.conn = pymongo.MongoClient()#'''建立无用户名密码连接'''
        cur_dir = '/'.join(os.path.abspath(__file__).split('/')[:-1])
        self.db = self.conn['medical']
        self.col = self.db['data']
        first_words = [i.strip() for i in open(os.path.join(cur_dir, 'first_name.txt'))]
        alphabets = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y', 'z']
        nums = ['1','2','3','4','5','6','7','8','9','0']
        self.stop_words = first_words + alphabets + nums
        self.key_dict = {
            '医保疾病' : 'yibao_status',
            "患病比例" : "get_prob",
            "易感人群" : "easy_get",
            "传染方式" : "get_way",
            "就诊科室" : "cure_department",
            "治疗方式" : "cure_way",
            "治疗周期" : "cure_lasttime",
            "治愈率" : "cured_prob",
            '药品明细': 'drug_detail',
            '药品推荐': 'recommand_drug',
            '推荐': 'recommand_eat',
            '忌食': 'not_eat',
            '宜食': 'do_eat',
            '症状': 'symptom',
            '检查': 'check',
            '成因': 'cause',
            '预防措施': 'prevent',
            '所属类别': 'category',
            '简介': 'desc',
            '名称': 'name',
            '常用药品' : 'common_drug',
            '治疗费用': 'cost_money',
            '并发症': 'acompany'
        }
        self.cuter = CutWords()

pymongo是一个方便使用数据库的库函数,首先按照刘老师注释所言,建立一个无用户名密码连接,然后定义一个指针变量,该变量使用os.path.abspath(只有当在脚本中执行的时候,os.path.abspath(__file__)才会起作用,因为该命令是获取的当前执行脚本的完整路径,如果在交互模式或者terminate 终端中运行会报没有__file__这个错误。)获取绝对路径。然后再获取该路径下的first_name.txt中的内容,构建一个first_words变量(os.path.join的作用是:连接两个或更多的路径名组件1.如果各组件名首字母不包含’/’,则函数会自动加上2.如果有一个组件是一个绝对路径,则在它之前的所有组件均会被舍弃3.如果最后一个组件为空,则生成的路径以一个’/’分隔符结尾)。

但是这个first_name.txt里面的内容却并没有在文件中给出,所以我们也不知道是以一个怎样的逻辑,但是我们有了最后构建好的json文件,所以这部分我们就当做背景知识的学习。

collect_medical():

    def collect_medical(self):
        cates = []
        inspects = []
        count = 0
        for item in self.col.find():
            data = {}
            basic_info = item['basic_info']
            name = basic_info['name']
            if not name:
                continue
            # 基本信息
            data['名称'] = name
            data['简介'] = '\n'.join(basic_info['desc']).replace('\r\n\t', '').replace('\r\n\n\n','').replace(' ','').replace('\r\n','\n')
            category = basic_info['category']
            data['所属类别'] = category
            cates += category
            attributes = basic_info['attributes']
            # 成因及预防
            data['预防措施'] = item['prevent_info']
            data['成因'] = item['cause_info']
            # 并发症
            data['症状'] = list(set([i for i in item["symptom_info"][0] if i[0] not in self.stop_words]))
            for attr in attributes:
                attr_pair = attr.split(':')
                if len(attr_pair) == 2:
                    key = attr_pair[0]
                    value = attr_pair[1]
                    data[key] = value
            # 检查
            inspects = item['inspect_info']
            jcs = []
            for inspect in inspects:
                jc_name = self.get_inspect(inspect)
                if jc_name:
                    jcs.append(jc_name)
            data['检查'] = jcs
            # 食物
            food_info = item['food_info']
            if food_info:
                data['宜食'] = food_info['good']
                data['忌食'] = food_info['bad']
                data['推荐'] = food_info['recommand']
            # 药品
            drug_info = item['drug_info']
            data['药品推荐'] = list(set([i.split('(')[-1].replace(')','') for i in drug_info]))
            data['药品明细'] = drug_info
            data_modify = {}
            for attr, value in data.items():
                attr_en = self.key_dict.get(attr)
                if attr_en:
                    data_modify[attr_en] = value
                if attr_en in ['yibao_status', 'get_prob', 'easy_get', 'get_way', "cure_lasttime", "cured_prob"]:
                    data_modify[attr_en] = value.replace(' ','').replace('\t','')
                elif attr_en in ['cure_department', 'cure_way', 'common_drug']:
                    data_modify[attr_en] = [i for i in value.split(' ') if i]
                elif attr_en in ['acompany']:
                    acompany = [i for i in self.cuter.max_biward_cut(data_modify[attr_en]) if len(i) > 1]
                    data_modify[attr_en] = acompany
 
            try:
                self.db['medical'].insert(data_modify)
                count += 1
                print(count)
            except Exception as e:
                print(e)
 
        return

 find() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果指定范围内如果包含指定索引值,返回的是索引值在字符串中的起始位置。如果不包含索引值,返回-1。item和basic_info都以字典的形式储存数据。

由于在该for循环中,定义了data字典,之后将有关该疾病的各种信息以键值对的形式存储到字典当中。首先是名称、简介信息(需要对其做一些修正然后才能保存)、疾病类别、预防措施、成因、症状。然后对于其他信息格式如XXX:XXX也同样进行存储,在冒号之后还有并列的情况之后处理。对于inspects中包含多个项目,在data['检查']下以列表的形式存储。最后是食物和药品。将这一切都存储到data中去后,在最后我们对data的格式进行最后一次修正,使用之前设定好的英文名。然后将其保存到数据库当中。

get_inspect():

    def get_inspect(self, url):
        res = self.db['jc'].find_one({'url':url})
        if not res:
            return ''
        else:
            return res['name']

待续

知识图谱基础代码构建(医疗向)_chen_nnn的博客-CSDN博客_构建知识图谱代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/109464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能制造数字化转型难点有哪些?

① 企业高层没有意识到数字化转型的必要性、紧迫性和复杂性,观念还停留在部署常用的IT系统。实际上,数字化转型远远不是IT部门能够实现的,必须由企业的决策层引领,自顶向下推进。 ② 企业已经应用了诸多信息系统,但是…

《MySQL高级篇》九、数据库的设计规范

文章目录1. 为什么需要数据库设计2. 范 式2.1 范式简介2.2 范式都包括哪些2.3 键和相关属性的概念2.4 第一范式(1st NF)2.5 第二范式(2nd NF)2.6 第三范式(3rd NF)2.7 小结3. 反范式化3.1 概述3.2 应用举例3.3 反范式的新问题3.4 反范式的适用场景4. BCNF(巴斯范式)5. 第四范式…

SOLIDWORKS Electrical 2023新功能揭秘!提高电气工程师设计效率 与机械工程师协同设计

SOLIDWORKS 2023新版本已经与大家见面,今天众联亿诚与大家分享SOLIDWORKS Electrical 2023新功能。 电气工程师在完成电气原理图设计的同时,还需要频繁地修改、导出各报表,使得大量时间浪费在重复性的手动工作上。即便如此,也无法…

【Python】Numpy中的Gumbel分布和Logistic分布

文章目录极值分GumbelLogistic分布极值分 设X1,X2…,XnX_1,X_2\dots,X_nX1​,X2​…,Xn​为从总体FFF中抽出的独立同分布样本,且 Mmax⁡(X1,…,Xn),mmin⁡(X1,…,Xn)M\max(X_1,\dots,X_n), m\min(X_1,\dots,X_n) Mmax(X1​,…,Xn​),mmin(X1​,…,Xn​) 若存在Cn&…

【Vue】利用v-model特性封装Dialog弹窗或可编辑窗口。

简单介绍&#xff0c;Vue里面的v-model就是vue的双向绑定的指令&#xff0c;能将页面上控件输入的值同步更新到相关绑定的data属性&#xff0c;也会在更新data绑定属性时候&#xff0c;更新页面上输入控件的值。 v-model封装弹窗 父组件 <manage-dialog v-model"isVis…

8年测试工程师,3年功能,5年自动化,浅谈我的自动化测试进阶之路...

前言 大家好我是小濠&#xff0c;本命马玉濠&#xff0c;已近从事测试行业8年了&#xff0c;自己也从事过3年的手工测试&#xff0c;从事期间越来越觉得如果一直在手工测试的道路上前进&#xff0c;并不会有很大的发展&#xff0c;所以通过自己的努力&#xff0c;早几年已经成…

2022巨量引擎城市峰会:发布重磅白皮书 提升城市繁荣力

12月21日&#xff0c;由巨量引擎城市研究院发起的年度城市盛典——《数说美好城市2022巨量引擎城市主题峰会》在上海隆重启幕。作为巨量引擎旗下专业城市研究机构&#xff0c;巨量引擎城市研究院在峰会期间发布了两份重磅报告:《2022美好城市指数白皮书》以及《2022都市圈发展力…

【Numpy基础知识】通用函数ufunc基础知识

通用函数(ufunc)基础知识 来源&#xff1a;Numpy官网&#xff1a;<https://numpy.org/doc/stable/user/basics.html 文章目录通用函数(ufunc)基础知识导包【1】Ufunc方法【2】输出类型确定【3】广播【4】类型转换规则【5】使用内部缓冲器【6】错误处理【7】覆盖ufunc行为导包…

【布局 widget】OverflowBox 与 SizedOverflowBox

OverflowBox 对于 OverflowBox ,文档只有一句话&#xff1a;把不同的约束强加给 child&#xff0c;允许 child overflow 父容器。这句话说的太简略了&#xff0c;使用的时候还是一头雾水&#xff0c;代码逻辑是这样的: BoxConstraints _getInnerConstraints(BoxConstraints co…

文科专业女生转行程序员月入20k:女生不适合做程序员吗?

背景故事 我毕业于某不知名985的经济学院&#xff0c; 19年毕业就跨考了计算机&#xff0c; 第一年考的是北大。北大专业课自主命题&#xff0c;考试范围包括慕课上的四门课408四门内容&#xff0c; 我就去做了炮灰。 第二年因为疫情和一些别的事情&#xff0c; 9月份开始准备考…

用 Python 制作各种用途的二维码

当你提到二维码时&#xff0c;大多数人想到的是仓库管理或产品标签等 "工业 "应用&#xff0c;但这篇文章在很大程度上是关于二维码的个人和社会用途。 有趣的事实 二维&#xff08;QR&#xff09;码是在1994年发明的&#xff0c;最近几年由于新冠肺炎的出现&#…

一道非常棘手的 Java 面试题:i++ 是线程安全的吗?

i 是线程安全的吗&#xff1f; 相信很多中高级的 Java 面试者都遇到过这个问题&#xff0c;很多对这个不是很清楚的肯定是一脸蒙逼。内心肯定还在质疑&#xff0c;i 居然还有线程安全问题&#xff1f;只能说自己了解得不够多&#xff0c;自己的水平有限。 先来看下面的示例来…

cache 缓存

缓存原理 测试样例 验证码 获取验证码 验证 验证码是否正确 idea 启动缓存 手机验证码 idea 手机 获得验证码 ehchace 数据淘汰策略 使用redis 然后启动 redis 服务器 redis-server.exe redis.windows.conf 启动redis 客户端redis-cli.exe time-to-live 最大活动时间 缓…

jsp+ssm计算机毕业设计职业中介信息管理系统【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

【蓝牙依赖】微信小程序 + uni通用,自用蓝牙依赖文件总结

引言 今年相较去年相比&#xff0c;做的比较多的是&#xff0c;蓝牙方面的对接工作。 因此&#xff0c;我整理了大半年来&#xff0c;对接蓝牙的经验&#xff0c;编写了蓝牙依赖文件。 这样可以有效的提升我的开发效率&#xff0c;以及合理增加我快乐的摸鱼时间 ~ 正文 废话…

ubuntu 安装supervisord

ubuntu 系统安装命令如下 sudo apt update && sudo apt install supervisor Supervisor服务在安装后自动运行&#xff08;这点从安装后创建的symlink到systemd的自启动服务可以看出&#xff09;。检查其状态&#xff1a; sudo systemctl status supervisor 如下安装…

基于SPRINGBOOT的高校羽毛球馆信息管理系统的设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a;基于springboot的高校羽毛球馆信息管理系统的设计与实现 模块划分&#xff1a;通知类型、通知信息、用户信息、用户充值、…

成功转行Python工程师,年薪30W+,经验总结都在这!

这是给转行做Python的小白的参考&#xff0c;无论是从零开始&#xff0c;或者是转行的朋友来说&#xff0c;这都是值得一看的&#xff0c;也是可以作为一种借鉴。 而且我决定转行IT&#xff08;互联网&#xff09;行业&#xff08;已转好几年&#xff09;&#xff0c;其实理由…

基于Java+Swing+mysql游泳馆会员管理系统

基于JavaSwingmysql游泳馆会员管理系统一、系统介绍二、功能展示1.管理员登陆2.主页面3.添加会员卡4.存款管理5.消费管理6.会员资料查询7.会员资料修改7.会员卡禁用、挂失三、系统实现1.StudentFrame .java四、其它1.其他系统实现一、系统介绍 该系统实现了管理员系统登陆、售…

四大领先优势加持,华为云会议服务更省心可靠!

&emsp;&emsp;随着数字化转型的加速&#xff0c;随时随地视频沟通和数据协作的工作方式加速走进各行各业&#xff0c;并衍生出丰富的行业应用场景。云会议融入到了行业的增值和业务创新中&#xff0c;如在线办公&#xff0c;在线教育&#xff0c;远程会诊&#xff0c;金…