作者 | AJ Gordon、June Alice

责编 | 屠敏

出品 | CSDN(ID:CSDNnews)

声明:本文仅作学习与交流。

在本文中,分析以“春雨医生”平台作为数据来源,通过Python抓取网站数据,结合“地市等级划分”数据,并再利用tableau制作地图和图表进行数据可视化。本文抓取的数据内容主要是全国范围内不同科室的TOP10医院名单,通过展示不同地区医院上榜的数量,以了解目前国内顶尖医疗水平的城市分布情况。由于本文采用的数据维度较少,结论仅供参考作用。

数据采集

首先,导入所需的库,再构建两个字典,一个存放地区编码,一个存放科室编码。利用两个嵌套for循环构建URL后,将全部URL存放到Redis数据库中,进行下一步操作。

import requests
from bs4 import BeautifulSoup
import pymysql
from concurrent.futures import ThreadPoolExecutor as Pool
from redis import ConnectionPool, Redis
import warnings
warnings.filterwarnings("ignore")
# 地区字典
area_dict = {'全国': '0','黑龙江省': '230000','吉林省': '220000','辽宁省': '210000','河南省': '410000','湖北省': '420000','湖南省': '430000','四川省': '510000','贵州省': '520000','云南省': '530000','重庆市': '500000','西藏自治区': '540000','陕西省': '610000','甘肃省': '620000','青海省': '630000','宁夏回族自治区': '640000','新疆维吾尔自治区': '650000','上海市': '310000','江苏省': '320000','浙江省': '330000','安徽省': '340000','福建省': '350000','江西省': '360000','山东省': '370000','台湾省': '710000','北京市': '110000','天津市': '120000','山西省': '130000','河北省': '140000','内蒙古自治区': '150000','广东省': '440000','广西壮族自治区': '450000','海南省': '460000','香港特别行政区': '810000','澳门特别行政区': '820000',
}
# 科室字典
department_dict = {'妇科':'1','儿科-小儿科':'fa','儿科-新小儿科':'fb','皮肤性病科-皮肤科':'ha','皮肤性病科-性病科':'hb','内科-呼吸内科':'aa','内科-心血管内科': 'ab','内科-神经内科': 'ac','内科-消化内科': 'ad','内科-肾内科': 'ae','内科-内分泌与代谢科': 'af','内科-风湿免疫科': 'ag','内科-血液病科': 'ah','内科-感染科': 'ai','男科':'8','产科':'21','外科-胸外科':'ba','外科-心脏与血管外科': 'bb','外科-神经外科': 'bc','外科-肝胆外科': 'bd','外科-烧伤科': 'be','外科-康复科': 'bf','外科-泌尿外科': 'bg','外科-肛肠科': 'bh','外科-普外科': 'bi','外科-甲状腺乳腺外科': 'bj','中医科-中医内科':'oa','中医科-中医外科': 'ob','中医科-中医妇科': 'oc','中医科-中医男科': 'od','中医科-中医儿科': 'oe','骨伤科-脊柱科':'ca','骨伤科-关节科': 'cb','骨伤科-创伤科': 'cc','精神心理科-精神科': 'na','精神心理科-心理科':'nb','口腔颌面科':'13','眼科':'15','耳鼻咽喉科-耳科':'ja','耳鼻咽喉科-鼻科': 'jb','耳鼻咽喉科-咽喉科': 'jc','肿瘤及防治科-肿瘤内科': 'ma','肿瘤及防治科-肿瘤外科': 'mb','肿瘤及防治科-介入与放疗中心': 'mc','肿瘤及防治科-肿瘤中医科':'md','整形美容科':'16','综合':'0',
}
# 收集url
def get_url():url = 'https://www.chunyuyisheng.com/pc/hospitallist/{}/{}/'for key1, value1 in area_dict.items():for key2, value2 in department_dict.items():url_new = url.format(value1, value2)redis_db.sadd('url_hospital', url_new)return None

然后,访问Redis数据库读取URL,利用ThreadPoolExecutor多线程抓取。抓取过程中有几点需要注意的:首先,访问频率过快的话,会出现503编码,解决办法是先跳过,稍后再访问;其次部分页面是无数据的,如果不进行剔除,会导致抓取过程卡住不动;此外有部分页面的医院所在城市标签为None,若不进行异常处理,也会导致卡住。最后,将抓取结果存入Mysql。

# 读取URL_1
def load_url_1():crawl_url_list = redis_db.smembers('url_hospital')while len(crawl_url_list) > 0:with Pool() as executor:futures = [executor.submit(get_content_1, crawl_url) for crawl_url in crawl_url_list]crawl_url_list = redis_db.smembers('url_hospital')
# 爬取Content_1
def get_content_1(crawl_url):conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='XX', db='analysis_data',charset='utf8', cursorclass=pymysql.cursors.DictCursor)r = requests.get(crawl_url, headers=headers)# 由于访问频率过高会导致服务器报错503,可先跳过,稍后再访问if r.status_code==503:print(r.status_code)# 由于部分网址的医院显示为无数据,需剔除这部分网址elif '暂无数据' in r.text:print('此页无数据。。。')redis_db.srem('url_hospital', crawl_url)else:soup = BeautifulSoup(r.text, 'lxml')all_content = soup.find_all('div', {'class': 'content'})[-1]# 获取医院详情页urlall_href = all_content.find_all('a')detail_url = ['https://www.chunyuyisheng.com/' + i['href'] for i in all_href]# 获取医院其它信息content_item = all_content.find_all('div', {'class': 'content-item'})for number, content in enumerate(content_item):hospital = content.find('div', {'class': 'top-title'}).get_text().strip()position_province = content.find('div', {'class': 'right-position'}).get_text().strip().split(' ')[0]# 由于部分医院的城市标签为None,可设置为Nonetry:position_city = content.find('div', {'class': 'right-position'}).get_text().strip().split(' ')[1]except:position_city = ''# 通过值找键,返回区域和科室area = crawl_url.split('/')[-3]department = crawl_url.split('/')[-2]def get_key(dict, value):return [k for k, v in dict.items() if v == value]area = get_key(area_dict, area)[0]department = get_key(department_dict, department)[0]# 由于部分医院的排名标签显示为None,且排名存在规律,可手工构建医院排名,保证排名字段不为空rank = area + department + '排名第' + str(number + 1)# 构建存储列表data = [area, department, hospital, rank, position_province, position_city,detail_url[number]]# 存入Mysqlwith conn.cursor() as cursor:sql1 = "create table if not exists `%s`(区域 varchar(255),科室 varchar(255),医院 varchar(255),排名 varchar(255),省份 varchar(255),城市 varchar(255),详细URL varchar(255)) character set utf8" % ('hospital_rank')cursor.execute(sql1)sql = "insert into hospital_rank(区域,科室,医院,排名,省份,城市,详细URL) values(%s,%s,%s,%s,%s,%s,%s)"cursor.execute(sql, data)conn.commit()print(data)redis_db.sadd('detail_url', detail_url[number])redis_db.srem('url_hospital', crawl_url)conn.close()

最后,抓取详情页中的医院等级资质,步骤与上面一样,结果存入Mysql中。

# 读取URL_2
def load_url_2():crawl_url_list = redis_db.smembers('detail_url')while len(crawl_url_list) > 0:with Pool() as executor:futures = [executor.submit(get_content_2, crawl_url) for crawl_url in crawl_url_list]crawl_url_list = redis_db.smembers('detail_url')
# 爬取Content_2
def get_content_2(crawl_url):conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='xx', db='analysis_data',charset='utf8', cursorclass=pymysql.cursors.DictCursor)r = requests.get(crawl_url, headers=headers)# 由于访问频率过高会导致服务器报错503,可先跳过,稍后再访问if r.status_code==503:print(r.status_code)else:soup = BeautifulSoup(r.text, 'lxml')hospital = soup.find('div', {'class': 'content-title'}).find('h3', {'class': 'title'}).get_text().strip()hospital_qualification = soup.find('div', {'class': 'content-title'}).find('span', {'class': 'label'}).get_text().strip()# 构建存储列表data = [hospital, hospital_qualification]# 存入Mysqlwith conn.cursor() as cursor:sql1 = "create table if not exists `%s`(医院 varchar(255),医院资质 varchar(255)) character set utf8" % ('hospital_qualification')cursor.execute(sql1)sql = "insert into hospital_qualification(医院,医院资质) values(%s,%s)"cursor.execute(sql, data)conn.commit()print(data)redis_db.srem('detail_url', crawl_url)conn.close()

数据处理

数据采集后,需要对数据进行清洗。先读取采集后的医院排名和资质数据,以及地市等级划分数据,然后无用字段可以剔除掉,可拆字段需进行拆分,合并多表后的结果,需检查字段的缺失值情况,并判断是否可进行填充。最后,由于展示结果中涉及到中国地图,由于tableau将台湾归为“国家”地理编码角色,需要手工追加一行记录,以便后期作图时能显示台湾部分。

import pandas as pd
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
# 加载数据
open_filepath = 'D:\pythondata\春雨医生\excel\\{}'
hospital_rank = pd.read_excel(open_filepath.format('hospital_rank.xlsx'),sheet_name='hospital_rank')
hospital_qualification = pd.read_excel(open_filepath.format('hospital_qualification.xlsx'),sheet_name='hospital_qualification')
city_grading = pd.read_excel(open_filepath.format('city_grading.xlsx'),sheet_name='city_grading')
province_area = pd.read_excel(open_filepath.format('city_grading.xlsx'),sheet_name='province_area')
# 处理数据
## 剔除无用字段
hospital_rank = hospital_rank.drop('详细URL',axis=1)
city_grading = city_grading.drop('排名',axis=1)
## 拆分字段
hospital_rank['科室1'] = hospital_rank.apply(lambda x:x['科室'].split('-')[0] if '-' in x['科室'] else x['科室'],axis=1)
hospital_rank['科室2'] = hospital_rank.apply(lambda x:x['科室'].split('-')[1] if '-' in x['科室'] else x['科室'],axis=1)
## 合并多表
result = pd.merge(hospital_rank,hospital_qualification,on='医院',how='left')
result = pd.merge(result,city_grading,on='城市',how='left')
result = pd.merge(result,province_area,on='省份',how='left')
## 填充字段
result['等级'] = result.apply(lambda x: '四/五线城市' if pd.isnull(x['等级']) else x['等级'],axis=1)
##
additional = pd.DataFrame({'区域':['全国'],'省份':['台湾省'],'城市':['台湾'],'地区':['华东']})
result = pd.concat([additional,result])
## 保存结果
result.to_csv(open_filepath.format('result.csv'),index=0, encoding="utf_8_sig")

数据可视化

首先,从地区维度去看,全国不同科室TOP10医院主要集中分布在华东和华北地区,华南和华中数量也不少。再从省份维度展示,主要分布在北京和上海,广东、天津、江苏和浙江分布数量也较多。

接着,从城市维度展示,可以看出大部分顶尖医院集中分布在北京、上海和广州这三座一线城市,南京、杭州和天津等新一线城市也占比不少。值得关注的是深圳作为一线城市,上榜的医院仅有1家,或许是历史和地理上的原因,但也说明深圳的医疗水平在国内来讲算不上是顶尖的。

从整体上看,顶尖医院主要分布在一线及新一线城市,少部分在二线城市,而二线外的城市均没有分布。此外,几乎所有顶尖医院都是三级甲等医院。

最后,将维度细分到科室的话,可以看到北京医疗水平是最顶尖的,覆盖了所有科室。上海和广州的医疗水平也位列前茅。新一线城市中,成都、杭州、南京和武汉这四个城市科室覆盖情况也很丰富,单从这里看的话,可以说医疗水平远超深圳,因为深圳只有心理科一个科室上榜。济南市作为一个二线城市,顶尖科室水平也较为不错。

结尾

此次分析仅从顶尖医院的数量来判断城市的医疗水平,采用的数据维度较少,分析不够全面,但科室这一维度来看,结果有一定的实践意义。例如有一鼻炎患者在深圳,就可以选择过去临近城市广州去看鼻科,因为那边有一家国内顶尖的医院,如此类推。也希望此次分析结果能帮助到有需要的人。

作者:AJ Gordon,对爬虫/机器学习/数据建模/可视化均有所涉猎的数据分析师;June Alice,在读研究僧一枚,跨行新手数据分析师。

【End】

《原力计划【第二季】- 学习力挑战》正式开始!
即日起至 3月21日,千万流量支持原创作者,更有专属【勋章】等你来挑战

推荐阅读 

☞6 岁学编程,9 岁给电脑杂志社撰稿,19 岁收月薪 2 万 的 Offer | 程序人生 2020

☞技术大佬:我去,你写的 switch 语句也太老土了吧!

☞赔偿谷歌1.8亿美元!前Uber自动驾驶主管被告到破产

☞乔布斯遗孀裸捐 250 亿美元财产:没兴趣累积财富

☞时间复杂度的表示、分析、计算方法……一文带你看懂时间复杂度!

☞闪电网络的 5 个优点和4 个缺点、本质、来源与工作原理……一文带你读懂闪电网络!

你点的每一个在看,我认真当成了喜欢

Python 数据分析实战,揭秘国内顶尖医院分布现状!相关推荐

  1. Python数据分析实战:上海二手房价分析

    1 数据搜集 使用 urllib 库中的request 模块爬取赶集网发布的上海二手房信息,包括包括户型.面积.单价等,再使用BeautifulSoup 库解析爬取的HTML数据,最终将数据保存到CS ...

  2. Python数据分析实战(3)Python实现数据可视化

    文章目录 一.数据可视化介绍 二.matplotlib和pandas画图 1.matplotlib简介和简单使用 2.matplotlib常见作图类型 3.使用pandas画图 4.pandas中绘图 ...

  3. python第四章课后答案4.7_Python数据分析实战作业 第四章 Python数据分析实战 习题...

    第四章 Python数据分析实战 习题(数据见附件sizhang.xlsx) 班主任现有一班级的两张表,如下. 表一:成绩表 学 号C#线 代Python 16010203788896 表二:信息表 ...

  4. Python数据分析实战(2)使用Pandas进行数据分析

    文章目录 一.Pandas的使用 1.Pandas介绍 2.Pandas基本操作 Series的操作 创建DataFrame 常见列操作 常见行操作 DateFrame的基本操作 时间操作 3.Pan ...

  5. 万字长文,Python数据分析实战,使用Pandas进行数据分析

    文章目录 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知道如何去学习更加高深的知识. 那么针对这三类人,我 ...

  6. Python数据分析实战基础 | 初识Pandas

    这是Python数据分析实战基础的第一篇内容,主要是和Pandas来个简单的邂逅.已经熟练掌握Pandas的同学,可以加快手速滑动浏览或者直接略过本文. 01  重要的前言 这段时间和一些做数据分析的 ...

  7. 《Python数据分析实战》day2: Pandas中取得某行或者是某列的一点思考

    今天看了<Python数据分析实战>这本书的第四章:Pandas的简介的部分,大概看了一半,在实践代码的时候发现了jupyter notebook提示warning,研究了一下有了一些自己 ...

  8. python数据分析实战 fabio nelli百度云_Python数据分析实战 内利(Fabio Nelli),杜春晓 9787115432209...

    商品描述: 基本信息 书名:Python数据分析实战 定**价:59.00元 作者: 内利(Fabio Nelli) 著,杜春晓 译 出版社:人民邮电出版社 出版日期:2016-08-01 ISBN: ...

  9. python电影数据分析报告_【python数据分析实战】电影票房数据分析(二)数据可视化...

    在上一部分<[python数据分析实战]电影票房数据分析(一)数据采集> 已经获取到了2011年至今的票房数据,并保存在了mysql中. 本文将在实操中讲解如何将mysql中的数据抽取出来 ...

最新文章

  1. NLP自然语言处理工具小结
  2. XMPP通讯开发-好友获取界面设计
  3. 币圈王哥:BTC多头局面进一步打开,BCH再现强势姿态
  4. 学习Kotlin(四)对象与泛型
  5. linux 串口驱动(二)初始化 【转】
  6. VMware10.0.4下 CentOS 6.5 cmake安装 MySQL 5.5.32
  7. 自己做网站翻译服务器 - 添加网站,猎场seo视频教程:站群之间应该如何进行链接-专业...
  8. 允许同站跨域Nginx配置方案
  9. javascript数据结构-栈
  10. seata执行闪退_Seata 1.2.0的配置以及踩坑记录
  11. 【C语言重点难点精讲】关键字精讲
  12. 信息学奥赛一本通(2034:【例5.1】反序输出)
  13. java的二叉树及三种遍历
  14. 精通HTML5+CSS3需要学什么?
  15. ai神经网络滤镜安装包
  16. 学习python-day01-13---转自Python分布式爬虫打造搜索引擎Scrapy精讲
  17. Reso | php面试题(mysql基础)
  18. linux p4 命令行,linux下使用P4(命令行)
  19. Java虚拟机(三)--------GC算法和收集器
  20. 黎曼积分并非战无不胜

热门文章

  1. 【Linux开发】Ubuntu下几个软件的配置记录backup
  2. 利用pagespeed插件优化网站css层叠样式文件
  3. [ubuntu] ubuntu20.04 卸载 firefox 下载 chrome
  4. h5在微信自定义分享php,h5页面自定义微信分享
  5. Linux Shell编程笔记9 SSH和Screen工具
  6. Flutter实战一Flutter聊天应用(十六)
  7. 绝缘端子行业调研报告 - 市场现状分析与发展前景预测
  8. uniac是哪一代计算机的代表,Saint-Uniac
  9. 从入门到入土:Python爬虫学习|实例练手|爬取猫眼榜单|Xpath定位标签爬取|代码
  10. Python菜鸟入门:day09数据结构