查看原文
其他

湖北省各市疫情数据爬取

爬虫俱乐部 Stata and Python数据分析 2022-03-15

本文作者:张馨月

文字编辑:朱巧利

技术总编:张计宝
在推文《卫健委的“糊涂账”》中,我们运用全国及湖北省内的疫情数据进行了分析,今天小编就以爬取湖北省各市新增患病人数为例,来带大家具体看看如何获取这些数据。

武汉市卫健委的官方网站上提供了疫情通报的专门界面。在此页面上查看源代码,能够观察到源代码中包含了我们需要的的标题、网址和日期。

(http://wjw.wuhan.gov.cn/front/web/list3rd/yes/802)

 

据此,我们就可按照如下三步来进行爬取:

1.获取所有通报情况的链接

2.从每条通报中爬取通报内容

3.从通报内容中提取各市信息


一、获取所有通报情况链接

虽然每日的通报链接都可以在源代码中找到,但是当我们点击下一页时,网址并没有发生变化,如果采用copy方式获得源代码,只能得到第一页的内容。这是因为该网页采取的请求方式不是“get”。在谷歌浏览器中点击F12进入开发者工具界面,刷新之后可以在network一栏中看到该网站采取的是post请求方式,因此我们需要采用curl方法模拟浏览器,并修改Form Data中的pageNum参数以进行爬取。关于这部分的内容,大家可以参考推文《一起来揪出网页真实链接!》《爬虫神器curl继续带你抓网页》。



比如,我们想要得到第二页的代码,就需要使用curl来请求,并对参数pageNum进行设置:

! curl "http://wjw.wuhan.gov.cn/front/web/list3rd/yes/802" --data "pageNum=2" -o temp.txt

从网页的源代码可以看到,所有网址的开头均为标题、网址和日期信息保留在标签“<ahref=http://wjw.wuhan.gov.cn:80/front/web/showDetail/和“<spanclass="time">"”当中,因此我们可以运用正则表达式保留下包含这两项的行。

infix strL v 1-100000 using temp.txt,clearkeep if ustrregexm(v,`"<a href="http://wjw.wuhan.gov.cn:80/front/web/showDetail|<span class="time">"')

为了让每日的信息在同一行中显示,我们可以用如下方法进行整理:

gen time=v[_n+1]keep if mod(_n,2)==1

接下来,用ustrregexs从变量v中提取出标题和网址,对time变量中的标签和具体发布时间用ustrregexra进行替换,便可整理得到所需的信息。 

gen title=ustrregexs(1) if ustrregexm(v,`"title="(.*?)">"') //提取标题replace time=ustrregexra(time,"<.*?>","") //将标签内容替换为空replace time=ustrregexra(time,"\s(.*)","") //将空格后的具体时间替换为空drop vcompressorder time title url


从标题中可以看到,每日提供的通报情况包括本省疫情状况以及全国疫情状况,因此我们可以再次使用正则表达式及起死回生命令preserverestore来分别保存全国及湖北省的数据。

*保存湖北通报preserve keep if ustrregexm(title,"湖北省")save "hubei_2.dta",replacerestore*保存全国通报preserve keep if ustrregexm(title,"湖北省")==0save "all_2.dta",replacerestore

为了得到所有页面的信息,需要把上述代码放入一个循环。不过这里有两点需要注意,首先,为了防止网速过慢导致爬取失败,可以在拷贝源代码时设置一个循环,当没有得到源代码时让程序休息一段时间再开始。其次,目前共有四页通报情况,但当我们爬取第五页时,依然可以获得源代码。不过,第五页中并不包括我们提取标题、网址和日期时用到的两个标签,所以如果在用正则表达式提取之后数据集中的内容为空,我们就可以跳出循环。具体程序如下:

clearforvalues i=1/10{ ! curl "http://wjw.wuhan.gov.cn/front/web/list3rd/yes/802" --data "pageNum=`i'" -o temp.txt while !fileexists("temp.txt") { sleep 5000 ! curl "http://wjw.wuhan.gov.cn/front/web/list3rd/yes/802" --data "pageNum=`i'" -o temp.txt } infix strL v 1-100000 using temp.txt,clear keep if ustrregexm(v,`"<a href="http://wjw.wuhan.gov.cn:80/front/web/showDetail|<span class="time">"') if _N == 0 { continue, break } gen time=v[_n+1] keep if mod(_n,2)==1
gen url=ustrregexs(1) if ustrregexm(v,`"<a href="(.*?)" title=""') gen title=ustrregexs(1) if ustrregexm(v,`"title="(.*?)">"') replace time=ustrregexra(time,"<.*?>","") replace time=ustrregexra(time,"\s(.*)","") drop v compress order time title url *保存湖北通报 preserve keep if ustrregexm(title,"湖北省") save "hubei_`i'.dta",replace restore *保存全国通报 preserve keep if ustrregexm(title,"湖北省")==0 save "all_`i'.dta",replace restore  }


二、获取通报内容

首先,我们把上一步中提取的湖北省每一页的数据合并在一起:

clearfs hubei*.dtaforeach file in `r(files)'{ append using `file'  }

接下来用fileread()函数来获取源代码,这样我们就能把每条通报的源代码都储存在一个变量中。

观察每一条源代码,可以发现通报的内容储存在“<divclass="TRS_Editor">”和“<div class="showprint">”标签之间,因此我们可以用split函数对这两个标签进行切分以获得通报内容。并使用正则表达式对空白字符、标签及其他无关内容进行替换。

gen content=fileread(url)split content,p(`"<div class="TRS_Editor">"' `"<div class="showprint">"')drop content content1 content3replace content2=ustrregexra(content2,"<.*?>","")replace content2=ustrregexra(content2,"&nbsp;","")replace content2=ustrregexra(content2,"\s","")

这样,便可得到每条公告的内容:


三、提取新增病患人数

通过观察每日的通报情况,可以发现每日的通报中会先通报当天新增病例数,再通报每日新增死亡数,因此我们可以使用“0(时)-24时”“新增死(病)亡”这些关键词对新增病患的情况进行提取。

rename content2 cogen content=ustrregexs(1) if ustrregexm(co,"0时-24时,(.*?)全省新增死亡")replace content=ustrregexs(1) if ustrregexm(co,"0—24时,(.*?)全省新增病亡")replace content=ustrregexs(1) if ustrregexm(co,"0时-24时,(.*?)全省新增病亡")replace content=ustrregexs(1) if ustrregexm(co,"新增确诊病例中(.*?)新增死亡")

这样,新生成的变量content中就保留了与新增病例有关的全部信息。


接下来,我们将湖北省各市的名称放入一个local中建立相应的变量并用正则表达式提取,以获取各市的疫情数据。

local city "武汉 孝感 黄冈 鄂州 随州 襄阳 天门 黄石 荆州 十堰 宜昌 仙桃 荆门 恩施州 咸宁 潜江"foreach x of local city { gen  `x' = ustrregexs(2) if ustrregexm(content,"(`x')(.*?)例")        }


但是如图所示,由此得到的数据格式并不规整,对此,我们可以先将“核减”用“-”代替,再将其他汉字替换为空:

foreach var in 武汉 孝感 黄冈 鄂州 随州 襄阳 天门 黄石 荆州 十堰 宜昌 仙桃 荆门 恩施州 咸宁 潜江 神农架{ replace `var'=ustrregexra(`var',"核减","-") replace `var'=ustrregexra(`var',"市|新增|首次发现|首发|林区|和神农架","")  }


运用这些数据,便可画出最初20天内各市疫情分布的热力图。这里我们使用的命令是heatplot,详细用法见推文《Stata绘制热力图详解》。在这里,我们需要将提取出的数据转换为数值型,同时,由于此处涉及到的变量较多,我们可以将这些数据先转化为矩阵,再画出图像。程序如下:

drop url title co contentgen date=date(time,"YMD")drop timereplace date=date-1format date %dn/Dgsort dateorder datedestring _all,replaceforeach v in 武汉 鄂州 天门 十堰 荆门 潜江 孝感 随州 黄石 宜昌 恩施州 黄冈 襄阳 荆州 仙桃 咸宁 神农架{ replace `v'=0 if `v'==. } mkmat 武汉 鄂州 天门 十堰 荆门 潜江 孝感 随州 黄石 宜昌 恩施州 黄冈 襄阳 荆州 仙桃 咸宁 神农架 if _n<21 ,matrix(C)mat C1=C'heatplot C1,values(format(%6.0f) mlabsize(*0.5)) color(hcl,diverging intensity(0.5)) xlabel(none) cut(0(10)1000) ramp(right space(15) subtitle("") label(@min "low" @max "high")) note("疫情爆发20天内湖北省新增人数",position(6) )


按照相同的思路,我们可以提取到各市新增死亡、累计患病的数据,大家动手试一试吧~

完整程序如下:

ap mkdir "d:\stata\疫情数据"cd "d:\stata\疫情数据"
*从武汉卫健委官网爬取疫情通报数据clearforvalues i=1/10{ ! curl "http://wjw.wuhan.gov.cn/front/web/list3rd/yes/802" --data "pageNum=`i'" -o temp.txt while !fileexists("temp.txt") { sleep 5000 ! curl "http://wjw.wuhan.gov.cn/front/web/list3rd/yes/802" --data "pageNum=`i'" -o temp.txt } infix strL v 1-100000 using temp.txt,clear keep if ustrregexm(v,`"<a href="http://wjw.wuhan.gov.cn:80/front/web/showDetail|<span class="time">"') if _N == 0 { continue, break } gen time=v[_n+1] keep if mod(_n,2)==1
gen url=ustrregexs(1) if ustrregexm(v,`"<a href="(.*?)" title=""') gen title=ustrregexs(1) if ustrregexm(v,`"title="(.*?)">"') replace time=ustrregexra(time,"<.*?>","") replace time=ustrregexra(time,"\s(.*)","") drop v compress order time title url *保存湖北通报 preserve keep if ustrregexm(title,"湖北省") save "hubei_`i'.dta",replace restore *保存全国通报 preserve keep if ustrregexm(title,"湖北省")==0 save "all_`i'.dta",replace restore }
*合并湖北数据clearfs hubei*.dtaforeach file in `r(files)'{ append using `file' }*爬取公告内容gen content=fileread(url)split content,p(`"<div class="TRS_Editor">"' `"<div class="showprint">"')drop content content1 content3replace content2=ustrregexra(content2,"<.*?>","")replace content2=ustrregexra(content2,"&nbsp;","")replace content2=ustrregexra(content2,"\s","")
*提取各市新增人数rename content2 co
gen content=ustrregexs(1) if ustrregexm(co,"0时-24时,(.*?)全省新增死亡")replace content=ustrregexs(1) if ustrregexm(co,"0—24时,(.*?)全省新增病亡")replace content=ustrregexs(1) if ustrregexm(co,"0时-24时,(.*?)全省新增病亡")replace content=ustrregexs(1) if ustrregexm(co,"新增确诊病例中(.*?)新增死亡") local city "武汉 孝感 黄冈 鄂州 随州 襄阳 天门 黄石 荆州 十堰 宜昌 仙桃 荆门 恩施州 咸宁 潜江 神农架" foreach x of local city {    gen  `x' = ustrregexs(2) if ustrregexm(content,"(`x')(.*?)例") }
foreach var in 武汉 孝感 黄冈 鄂州 随州 襄阳 天门 黄石 荆州 十堰 宜昌 仙桃 荆门 恩施州 咸宁 潜江 神农架{ replace `var'=ustrregexra(`var',"核减","-") replace `var'=ustrregexra(`var',"市|新增|首次发现|首发|林区|和神农架","") }compress
***湖北省内疫情分布drop url title co contentgen date=date(time,"YMD")drop timereplace date=date-1format date %dn/Dgsort dateorder datedestring _all,replaceforeach v in 武汉 鄂州 天门 十堰 荆门 潜江 孝感 随州 黄石 宜昌 恩施州 黄冈 襄阳 荆州 仙桃 咸宁 神农架{ replace `v'=0 if `v'==. } mkmat 武汉 鄂州 天门 十堰 荆门 潜江 孝感 随州 黄石 宜昌 恩施州 黄冈 襄阳 荆州 仙桃 咸宁 神农架 if _n<21 ,matrix(C)mat C1=C'heatplot C1,values(format(%6.0f) mlabsize(*0.5)) color(hcl,diverging intensity(0.5)) xlabel(none) cut(0(10)1000) ramp(right space(15) subtitle("") label(@min "low" @max "high")) note("疫情爆发20天内湖北省新增人数",position(6) )
save hubei_data,replace




对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!
往期推文推荐

古代诗人总去的这些地方你一定要知道!

DataFrame数组常用方法(二)

ftools命令——畅游大数据时代的加速器

卫健委的“糊涂账”

Pandas中数据的排序与切片

DataFrame数组常用方法

巧用局部宏扩展函数dir

过了14天潜伏期真的没事了?

Pandas基本数据类型介绍

NumPy数组基本介绍

“个性化”sortobs命令,教你实现排序自由

携手战疫,我们在行动

恭贺新春,平安顺遂|各省疫情关注度地图

过年观影指南(二)

过年观影指南(一)

egenmore隐藏功能——进制转换

相遇insobs,如暗室逢灯

数据可视化之地理坐标系

关于我们


微信公众号“Stata and Python数据分析”分享实用的stata、python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。

此外,欢迎大家踊跃投稿,介绍一些关于stata和python的数据处理和分析技巧。
投稿邮箱:statatraining@163.com
投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存