2022软工K班个人编程任务

一、PSP表格

首先是我的Github链接(点我)

  • (2.1)在开始实现程序之前,在附录提供的PSP表格记录你估计将在程序的各个模块的开发上耗费的时间。**

PSP2.1Personal Software Process Stages预估耗时(分钟)
Planning计划60
· Estimate· 估计这个任务需要多少时间10
Development开发2000
· Analysis· 需求分析 (包括学习新技术)540
· Design Spec· 生成设计文档60
· Design Review· 设计复审30
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)15
· Design· 具体设计90
· Coding· 具体编码1000
· Code Review· 代码复审120
· Test· 测试(自我测试,修改代码,提交修改)120
Reporting· 计算工作量30
·· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划30
· 合计4105
  • (2.2)在你实现完程序之后,在附录提供的PSP表格记录下在程序的各个模块上实际花费的时间。

PSP2.1Personal Software Process Stages预估耗时(分钟)
Planning计划60
· Estimate· 估计这个任务需要多少时间20
Development开发1500
· Analysis· 需求分析 (包括学习新技术)640
· Design Spec· 生成设计文档60
· Design Review· 设计复审15
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)60
· Design· 具体设计180
· Coding· 具体编码1200
· Code Review· 代码复审30
· Test· 测试(自我测试,修改代码,提交修改)180
Reporting· 计算工作量20
·· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划30
· 合计3995

二、任务要求的实现

  • (3.1)项目设计与技术栈。从阅读完题目到完成作业,这一次的任务被你拆分成了几个环节?你分别通过什么渠道、使用什么方式方法完成了各个环节?列出你完成本次任务所使用的技术栈。

我将本次个人编程作业分为四个环节,分别为计划、学习、开发、总结。
所用技术栈selenium+pyecharts+BeautifulSoup+time+re+xlwt
(1) 计划环节中,我先仔细阅读了发布的作业要求,提取出“疫情数据获取”、“exce表格”、“数据可视化”等关键点,确定了使用python来进行疫情数据的爬取,并上网查询了“疫情可视化”相关案例,学习他们的整体思路,并构思出程序的框架,用PSP表格记录下在各个模块上开发的预估耗时。
(2) 学习环节中,通过CSDN、博客园等平台学习了request、selenium、beautifulSoup等各种工具的使用方法。
(3) 开发环节中,我使用Pycharm软件来进行程序开发。利用构思好的程序框架,先将程序的主要结构(函数)写出来,再通过不断调试与完善,逐步地编写代码,记录下开发过程中所遇到的问题。
(4) 总结环节中,回顾整体代码,详细列出实现代码的整体思路以及解决问题的思路,通过几个案例的测试,也总结出了代码的局限性与不足性。

  • (3.2)爬虫与数据处理。说明业务逻辑,简述代码的设计过程(例如可介绍有几个类,几个函数,他们之间的关系),并对关键的函数或算法进行说明。

本代码一共设计了如下几个函数

def getpage()
def getTime(url_text)
def getLocal_add(url_text)
def getNoSymptom_add(url_text)
def getHMT_people(url_text)
def add_data(a,b)
def write_to_excel(filename, dict1,dict2)
def  getMap(fileName,a,b)

(1) 页面获取getpage()
由于卫健委的反爬机制,用谷歌浏览器与request等方法较难爬取到数据,后来在CSDN看到了一位博主的案例后,我使用了selenium+火狐浏览器来爬取网页。
在这里插入图片描述
在疫情通报列表页面,我们可以看到第一页网址为:http://www.nhc.gov.cn/xcs/yqtb/list_gzbd.shtml
第二页网址为:http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_2.shtml
第三页http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_3.shtml……以此类推
于是我们可以得出它的页面除了了第一页,其他的构成为http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_(数字).shtml
因此,我们使用一个getPage()函数来顺序获取并返回页面的链接

def getpage():   #页数函数
    for page in range(1,42):
        if page == 1:
            yield'http://www.nhc.gov.cn/xcs/yqtb/list_gzbd.shtml'
        else:
            url = 'http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_'+str(page)+'.shtml'
            yield url

在获取了疫情通报的页码后,我们要做的就是爬取到该页上所有新闻链接,在主函数中,我们通过for …in…来进入每个页码的网站,然后使用selenium以及火狐浏览器爬取到该页码上所有新闻链接,再使用for…in…进入每一个新闻链接进行内容爬取

def main():
    for url_main in getpage():  #从第一页开始爬取该页的所有新闻链接

        option = FirefoxOptions()
        option.add_argument("--headless")  # 隐藏浏览器
        browser = Firefox(executable_path='geckodriver', options=option)
        browser.get(url_main)
        time.sleep(3)   #设置等待时间
        data = browser.page_source
        soup = BeautifulSoup(data, "lxml") #创建对象
        url_list = soup.find('div', class_='list').find_all('li')  #找到list中的所有li标签

        for i in url_list:
            url =  'http://www.nhc.gov.cn/' + i.find('a')['href'] #爬取a标签下href的内容,需要加上网址头
            try:
                #接下来爬取单独的网页
                browser.get(url)
                time.sleep(3)  
                ##中间为按顺序调用的子函数
            except Exception:
                contine
            time.sleep(3)
        time.sleep(3)
        browser.quit()
main()

(2)时间获取getTime()
在详细疫情通报的页面源代码中,我们可以看到发布新闻的年月日,以及新冠肺炎疫情情况的截止月日,各差了一天。
在这里插入图片描述
我们需要的是疫情情况的截止年月日,使用正则表达式,可以爬取class=source里的第三个span标签获取年,爬取class = tit里的月日,再进行特殊情况的处理,并获得我们文件的名字。

def getTime(url_text): 
    ....#正则表达式部分太多,不列出
    #Title_Get为一个列表,存储截止日期[月,日],release_Get 存储[年,月,日 ]
    if int(Title_Get[0])<int(release_Get[1]): #如果发布新闻的月份比通报的疫情日期还小,则年份要减一
        Title_year_Get= str(int(release_Get[0])-1)
    else:
        Title_year_Get = str(int(release_Get[0]))
    Title_month_Get = Title_Get[0]
    Title_day_Get = Title_Get[1]
    Time=(Title_year_Get+'年'+Title_month_Get+'月'+Title_day_Get+'日新型冠状病毒肺炎疫情')
    return Time  #返回一个文件标题

(3)内陆省份以及新增确诊人数获取 getLocal_add()、内陆新增无症状感染人数获取getNoSymptom_add()
这两个函数的功能实现都相同,都是在主函数里面调用,传入的参数为主函数里爬取到的页面数据,然后在子函数里创建一个soup,然后用正则表达式爬取出来省份、确诊人数或者感染人数,组合成一个字典,并返回给主函数里的变量。下面为函数的核心算法部分

     ...正则表达式部分太多就不展出了,下同
    province_list 为爬取数据后,存储有疫情的省份的列表
    province_people为存储对应人数的列表
    ll = [0]*len(province)  #创建一个跟省份数目相同的全为‘0’的列表
    在getLocal_add()中
    nubmtuple = tuple(zip( map(int, province_people),ll)) #将确诊人数设置为(x,0)的元组
    在getNoSymptom_add()中
     nubmtuple = tuple(zip( ll,map(int, province_people))) #将无症状感染设置为(0,x)的元组
    a=dict(zip(province,nubmtuple))
    return a

下图为getLocal_add()函数得到的结果
(4)港澳台累计确诊统计getHMT_people()
原理和(3)中差不多,港澳台地区由于没有找到历史的当日新增感染人数 的新闻数据,就只统计了截至日期的累计确诊人数

 people_num 列表用来存储爬取到的每个地方的累计确诊人数
 province = ["香港","澳门","台湾"] 
 add = dict(zip(province,map(int,people_num))) #组合成一个列表

(6)数据合并add_data(a,b)
在上述步骤中,我们获得了例如{‘云南’,(0,4)}的新增确诊字典以及{‘福州’,(0,12)}的新增无症状感染人数的字典,接下来关键的一步就是将两个字典合并。在主函数中,我们调用add_data()函数,并传入上述步骤获得的两个字典的参数。算法如下

    for i in b.keys():  #嵌套两个循环,从第一个字典的键开始查找是否跟第二个字典的键相匹配,匹配则将感染人数的两个信息合并,没有匹配项则增加到字典中
        flag =0
        for j in a.keys():
            if i == j:
               a[j]=(a[j][0],b[i][1])
               flag=1
               break
        if flag==0: #如果a字典的键中没有b的某一个键,则增加到a中
            a[i]=(b[i][0],b[i][1])
    return a

这样就得到了一个用字典存储的完整的疫情信息,字典的value值存储一个元组,元组第一个值为确诊人数,第二个值为无症状感染人数
在这里插入图片描述
(7)数据导入exceldef write_to_excel(filename, dict1,dict2)
该函数中,传入的第一个参数为getTime()返回给给主函数的标题,第二个参数为数据合并(add_data(a,b))后的内地疫情字典,第三个为港澳台疫情情况的字典。
我利用了xlwt工具来进行excel导数据,并创建了两张工作表,一张为内地疫情明细,一张为港澳台疫情明细,保存成名为filename的xls文件。核心算法如下所示

        j=1 
        for content1 in dict1.items():#写入内地疫情,用concent迭代字典的每一个键值对,并在j行的0、1、2列写入省份、确诊人数、无症状感染人数的数据
            sheet1.write(j, 0,content1[0])
            sheet1.write(j, 1, content1[1][0])
            sheet1.write(j, 2, content1[1][1])
            j=j+1

得到的结果如下图
在这里插入图片描述在这里插入图片描述

(8)可视化地图制作getMap(fileName,a,b)
详情看下(3.5)

(9)程序运行结果展示
最后就是爬虫后数据处理结果的展示啦。程序运行过程中,爬取以及数据处理成功后会输出提醒语句,excel以及可视化地图页面都自动存入了文件夹中。
在这里插入图片描述在这里插入图片描述

  • (3.3)数据统计接口部分的性能改进。记录在数据统计接口的性能上所花费的时间,描述你改进的思路,并展示一张性能分析图,并展示你程序中消耗最大的函数。

我在数据统计接口上所花费的时间非常大,主要时间都花费在了页面中省份以及人数的数据检索。一开始打算直接用request或者soup来直接在整个url的文本上抓取省份名称以及人数,但是发现卫健委页面上的人数是在span和/span中间,导致我很难直接将数字单独检索出来。在最后就只能对应到本土病例以及无症状感染的标签上,然后再用正则表达式检索出来。
我使用了profile和pstats来作为性能分析工具,由于将所有页面爬出来的程序过慢,所以在这边展示爬取一次页面的,按时间排序的一部分结果。

profile.run('main()', "result")
pstats.Stats('result').sort_stats('time').print_stats()

在这里插入图片描述

  • (3.5)数据可视化界面的展示。在博客中介绍数据可视化界面的组件和设计的思路。

同样,我们在主函数中调用可视化界面制作的函数getMap(fileName,a,b),第一个参数作为标题,第二个参数为内地疫情的字典,第三个参数为港澳台疫情的字典。
在过程中,我使用了pyecharts工具来制作一个地图类的可视化界面,一个地图中有三个元素,分别为内地新增确诊人数,内地新增无症状感染者,港澳台累计确诊人数。
由于Map().add()函数中,第二个参数为中国省份以及数据的一个或多个列表,所以我们首先需要通过设置一个迭代来获得我们字典里面的内容,并转换成list列表
迭代的z是一个省份和人数的元组,如(‘浙江’,(14,5)),14代表确诊,5代表无症状,这时候我们要将z转换成list形式,并分别取出省份名称和确诊人数(或无症状感染人数、累计确诊人数),又讲其转换为list列表,如[‘浙江’,‘14’],[‘浙江’,‘5’].
最后生成一份本地html。
实现的算法如下

 map1 = (   
     Map(init_opts=opts.InitOpts(width="1500px",height="600px"))
         .add("新增确诊人数", [list((list(z)[0], str(list(z)[1][0])))   #在此只展示新增确诊人数的设计,其余二者都类似操作,只是选择的数据不同
                       for z in zip(list(a.keys()), list(a.values()))], "china")
         .set_global_opts(
         title_opts=opts.TitleOpts(title=fileName),
         visualmap_opts=opts.VisualMapOpts(max_=300, split_number=20, is_piecewise=True, ),
     )
 )
 map1.render(fileName + '.html')# 生成到本地网页形式打开

地图可以实现放大缩小、鼠标互动展示的功能,我们可以通过需求查看不同类型的疫情情况
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

三、心得体会

这部分怎么写呢,百感交集。

这大概是我入学以来最奋斗的两个周,从任务的最终发布到开始上网收集材料制定计划,从第一行代码到完成运行整个程序,整个开发过程基本上靠自己学习,每一个步骤、每一行代码都是用心血苦苦熬出来的。也有参考网上的各种案例,看着他们的方法自己去学习如何搭建程序,json、Pyppeteer、request等各种方法一一比对,在不断的错误与尝试中最终定下了我易于理解与掌握的方法。程序中我用到的方法最多的就是正则表达式了吧,爬取到网页信息后,先筛选出我所需要的标签内容,再用正则表达式测试器一遍一遍琢磨如何匹配出我所想要的内容,再到构思如何将数据合并、转换、修改,这过程确实很痛苦。

但是由于我选择的方法以及整体代码框架的局限性,我目前无法将所获得的单独的数据结合起来,导致没有方向去编写每日数据对比的算法,只能静态地展示每天的疫情数据,缺乏互通性。

但收获也颇多,虽然我曾经上过pyhton编程课,但我们主要学习了基础语法,并没有教学爬虫相关的内容。在本次个人作业中,我自己学习了丰富的爬虫内容,正则表达式、beautifulsoup等等相关的语法都在编程中逐渐掌握熟练,最终能够做出疫情信息爬取与可视化展示的程序。

我真的很不戳😎 😎

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值