2022软工K班个人编程任务

一、PSP表格

PSP预估耗时(分钟)实际耗时(分钟)
计划1010
估计这个任务需要多少时间56
开发720900
需求分析600720
生成设计文档2030
设计复审54
代码规范22
具体设计60180
具体编码360280
代码复审6030
测试30180
报告120110
测试报告00
计算工作量2030
事后总结3060
合计20122542

二、任务要求的实现

1.项目设计与技术栈

这一次任务被我拆分成了6个环节,分别是:
1.从零学习python与爬虫
2.通过爬虫获取要爬取的所有页面的url
3.通过爬虫爬取目的文本
4.对目的文本的处理,提取疫情数据
5.每日热点的实现
6.数据的可视化处理

完成各个环节的方法:
123.通过上网查询相关书籍、代码、视频学习爬虫
4.学习python处理爬到的文本,用到了beautifulsoup和正则表达式
5.根据所得数据分析,结合实际自主设计实现每日热点
6.学习使用excel等工具构建数据可视化动态展示
技术栈:JavaScript+Python+Excel+Pycharts

2.爬虫与数据处理

本次在爬虫上我所用的时间最长,遇到的主要问题是:所爬网站存在反爬机制,对于我这个之前从没用过爬虫的小萌新来说是个不小的挑战。

爬虫的实现:

因为反爬机制,用request指令经常爬不到正常的网页信息,返回412和爬到一堆乱码是两大难以解决的问题,因此我选择使用selenium来编写爬虫,部分代码如下:

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
def get_request(url):      #selenium爬虫,返回网页源码
    while 1:
        driver = webdriver.Chrome(options=chrome_options)  # 设置引擎为Chrome,在后台默默运行
        driver.get(url)
        EC_title = EC.title_contains('日') #爬取成功检测
        print(EC_title(driver))
        if EC_title(driver):
            break
        print('ERROR')
        driver.close()

    print('succeed!')
    # print(con.text)
    return driver.page_source

通过循环访问页面,直到判断语句判定爬取了正确的内容后,返回所爬页面的源码。运用了selenium模拟访问网页,这种方法的优点是稳定,不会因为爬取到错误代码而导致程序中止;缺点是selenium耗时较长。
顺带附上我爬取所有网址的部分代码,使用的是request方法:

def parse_single_html(html):#爬取链接
    soup=BeautifulSoup(html.text,'html.parser')
    datas=[]
    title_nodes=(#返回了一个列表
        soup
        .find("ul",class_="zxxx_list")
        .find_all("a")
    )
    for atitle in title_nodes:
        link = atitle["href"]
        datas.append(link)

    return datas

def download_all_htmls():
    htmls=[]
    for idx in range (41):
        if idx==0:
            url = 'http://www.nhc.gov.cn/xcs/yqtb/list_gzbd'
        else:
            url=f"http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_{idx+1}"

        print("craw html:",url)
        while 1:
            con=requests.get(url,headers=headers)
            con.encoding = 'utf-8'
            print(con)#获取并输出
            if con.status_code ==200:#爬取成功则跳出循环
                break
            time.sleep(0.5)#重爬间隔
        htmls= htmls+parse_single_html(con)
        print(parse_single_html(con))
        print(htmls)
        time.sleep(0.5)
    f = open("htmls.txt", "w")
    for ahtml in htmls:  # 将所得所有url导入txt文档中
        f.write('http://www.nhc.gov.cn')
        f.write(ahtml + '\n')
    f.close()
    return htmls

数据处理

数据处理先利用BeautifulSoup处理网页源码,获取到网页中正文的文本信息(实现很方便),然后利用正则表达式提取出带有关键字词、目标格式的信息。部分代码如下:

def deal_data():
    datas = open("data.txt", "w")#data.txt中存放提取的数据
    htmls=[]
    f=open("htmls.txt","r",encoding='utf-8')#读取txt文件中存储的网址
    line=f.readline()
    while line:

        htmls.append(line.rstrip('\n'))#输入网页时不能带换行符,这里将其删去
        line=f.readline()
    f.close()
    iu=0
    for urls in htmls:

        iu=iu+1
        if iu>972:
            break
        summary= len(htmls)
        print(urls)
        print('爬取网址',iu,'共有',summary,'个')
        url = urls
        con = get_request(url)   #爬取爬取

        texts = con
        result = BeautifulSoup(texts, 'lxml')  # html.parser

        div1 = result.find('title')#提取网页标题,目的是获取日期信息
        print(div1)
        div_date=re.search('[0-9]+月[0-9]+日',str(div1))
        print(div_date.group())#成功提取日期

        div2 = result.find('div', attrs={'class': 'con'})

        div_def = div2.text.replace('\xa0' * 4, '\n\n\xa0\xa0')#处理网页正文部分
        div_def = div_def.replace('(注:媒体引用时,请标注“信息来自国家卫生健康委员会官方网站”。)','')
        div_def = div_def.replace('分享到','')

        div_x=(re.search('新增确诊病例([\s\S]*?)\n',str(div_def)) or NoMatch)#通过正则提取
        div_x=(re.search('本土([\s\S]*?))',str(div_x.group())) or NoMatch)
        print(div_x.group())
        div_bentuxinzeng=re.findall('河北[0-9]+|山西[0-9]+|辽宁[0-9]+|吉林[0-9]+|黑龙江[0-9]+|江苏[0-9]+|浙江[0-9]+|安徽[0-9]+|福建[0-9]+|江西[0-9]+|山东[0-9]+|河南[0-9]+|湖北[0-9]+|湖南[0-9]+|广东[0-9]+|海南[0-9]+|四川[0-9]+|贵州[0-9]+|云南[0-9]+|陕西[0-9]+|甘肃[0-9]+|青海[0-9]+|台湾[0-9]+|内蒙古[0-9]+|广西[0-9]+|西藏[0-9]+|宁夏[0-9]+|新疆[0-9]+|北京[0-9]+|天津[0-9]+|上海[0-9]+|重庆[0-9]+|香港[0-9]+|澳门[0-9]+|例[0-9]+例(在[\s\S]*?)',str(div_x.group()))

        print(div_bentuxinzeng)
        numlist = re.findall('[0-9]+', str(div_bentuxinzeng))  ##分离列表
        prolist = re.findall(
            '河北|山西|辽宁|吉林|黑龙江|江苏|浙江|安徽|福建|江西|山东|河南|湖北|湖南|广东|海南|四川|贵州|云南|陕西|甘肃|青海|台湾|内蒙古|广西|西藏|宁夏|新疆|北京|天津|上海|重庆|香港|澳门|台湾',
            str(div_bentuxinzeng))
        pro1list=(prolist)
        num1list=(numlist)
        print(pro1list)
        print(num1list)#最终得到两个一一对应的列表

        for i in range(len(pro1list)):#将数据写入txt
            datas.write(div_date.group())
            datas.write(',')
            datas.write(pro1list[i])
            datas.write(',')
            datas.write(num1list[i]+'\n')
            
        div_x = (re.search('新增无症状([\s\S]*?)\n', str(div_def)) or NoMatch)#同上,提取本土新增无症状
        div_x = (re.search('本土([\s\S]*?))', str(div_x.group())) or NoMatch)
        print(div_x.group())
        div_wuzhengzhuangxinzeng=re.findall('河北[0-9]+|山西[0-9]+|辽宁[0-9]+|吉林[0-9]+|黑龙江[0-9]+|江苏[0-9]+|浙江[0-9]+|安徽[0-9]+|福建[0-9]+|江西[0-9]+|山东[0-9]+|河南[0-9]+|湖北[0-9]+|湖南[0-9]+|广东[0-9]+|海南[0-9]+|四川[0-9]+|贵州[0-9]+|云南[0-9]+|陕西[0-9]+|甘肃[0-9]+|青海[0-9]+|台湾[0-9]+|内蒙古[0-9]+|广西[0-9]+|西藏[0-9]+|宁夏[0-9]+|新疆[0-9]+|北京[0-9]+|天津[0-9]+|上海[0-9]+|重庆[0-9]+|香港[0-9]+|澳门[0-9]+|例[0-9]+例(在[\s\S]*?)',str(div_x.group()))
        print(div_wuzhengzhuangxinzeng)
        numlist = re.findall('[0-9]+', str(div_wuzhengzhuangxinzeng))  ##分离列表
        prolist = re.findall(
            '河北|山西|辽宁|吉林|黑龙江|江苏|浙江|安徽|福建|江西|山东|河南|湖北|湖南|广东|海南|四川|贵州|云南|陕西|甘肃|青海|台湾|内蒙古|广西|西藏|宁夏|新疆|北京|天津|上海|重庆|香港|澳门|台湾',
            str(div_wuzhengzhuangxinzeng))
        pro2list = (prolist)
        num2list = (numlist)
        print(pro2list)
        print(num2list)
        
                for i in range(len(pro2list)):
            datas.write(div_date.group())

            datas.write(',,,')#控制格式导入excel中
            datas.write(pro2list[i])

            datas.write(',')
            datas.write(num2list[i] + '\n')

数据处理的难点在于一些早些网页的文本格式和近期不同,要额外考虑,导致代码冗长。

3.数据统计接口部分的性能改进

本次作业在花费时间方面,爬虫耗时在我对其“改进”后成倍增长(反爬机制确实遭不住啊),时间关系,在本次作业中我没有多的时间去探索一个更好的爬虫方法,不过今后我还要探索更加省时还能正常爬取网页的方法。
消耗最大的函数:deal_data()中的get_request(url)

4.每日热点的实现思路

我通过分析每一天所爬的数据,人为制定出一个标准,主要通过判断语句对数据进行分析,对当日中国本土以及各个省份的疫情情况作出简单的判断,与疫情数据一起写入excel中。部分代码如下:

summm1 = 0                 #每日热点模块,根据人数对疫情进行分析研判
        summm2 = 0
        for i in range(len(pro1list)):
            summm1 = summm1 + int(num1list[i])
            if int(num1list[i]) > 40:
                datas.write(div_date.group())
                datas.write(',,,,,,,')
                datas.write(pro1list[i] + '省')
                datas.write('新增本土确诊人数为:')
                datas.write(num1list[i])
                datas.write('。防疫形势严峻。\n')
        for i in range(len(pro2list)):
            summm2 = summm2 + int(num2list[i])
            if int(num2list[i]) > 200:
                datas.write(div_date.group())
                datas.write(',,,,,,,')
                datas.write(pro2list[i] + '省')
                datas.write('新增本土无症状感染者人数为:')
                datas.write(num2list[i])
                datas.write('。防疫形势严峻。\n')
        if summm1==0:
            datas.write(div_date.group())
            datas.write(',,,,,,,')
            datas.write('好耶!无本土新增确诊!\n')
        if summm2==0:
            datas.write(div_date.group())
            datas.write(',,,,,,,')
            datas.write('好耶!无本土新增无症状感染者!\n')
        if summm1 > 0:
            datas.write(div_date.group())
            datas.write(',,,,,,,')
            datas.write('新增本土确诊人数为:')
            datas.write(str(summm1))
            if summm1 < 25:
                datas.write('。总体态势良好。\n')
            elif summm1 < 50:
                datas.write('。仍有潜在危险。\n')
            elif summm1 < 200:
                datas.write('。形势并不乐观。\n')
            else:
                datas.write('。防疫形势严峻。\n')
            if (int(num1list[0]) >= summm1 / 2):
                datas.write(div_date.group())
                datas.write(',,,,,,,')
                datas.write(pro1list[0])
                datas.write('为重点防控省份。\n')
        if summm2 > 0:
            datas.write(div_date.group())
            datas.write(',,,,,,,')
            datas.write('新增本土无症状感染者人数为:')
            datas.write(str(summm2))
            if summm2 < 50:
                datas.write('。总体态势良好。\n')
            elif summm2 < 200:
                datas.write('。仍有潜在危险。\n')
            elif summm2 < 1000:
                datas.write('。形势并不乐观。\n')
            else:
                datas.write('。防疫形势严峻。\n')
            if (int(num2list[0]) >= summm2 / 2):
                datas.write(div_date.group())
                datas.write(',,,,,,,')
                datas.write(pro2list[0])
                datas.write('为重点防控省份。\n')

这种实现方法的优点:直观,有严格的判定方法。
缺点:不够全面,过于直板。

5.数据可视化界面的展示

数据可视化我选择的是利用基于Pycharts的WPS-excel,操作简单,内容直观。通过利用excel所提供的数据透视表和透视图技术,能够实现数据的动态化展示和一定的交互功能。界面展示如下:
在这里插入图片描述
页面左侧是每日新增确诊Top10和每日新增无症状Top15的省份,能够直观地看出全国的防疫重心应该放在哪个位置。右侧是对某个省份的新增确诊和无症状感染者的趋势图,利用折线统计图实现了对某个省疫情情况有记录的近10天的趋势。
中间部分是日期的选取和省份的选取,分别对应左右两侧的功能。
港澳台因为其特殊性,我单独列出置于中下部,今日热点置于右下方,会根据所选日期变化。

三、心得体会

本次个人编程任务我所耗时间略高于预计时间,其实我的估计时间已经放很宽了(个人认为),但实际用时更长,其主要原因是我在编程过程中遇到了比预想中更多的问题,从对抗网页的反爬机制到数据处理、数据可视化,我的实际用时都远超预计。我也是第一次感觉到即使熬夜学习,时间还是略显紧凑的感觉。

发现自己的问题:学习容易精力不集中,有些效率低下,导致时间消耗过多。

今天回头看看,我这用时约有四十多小时的作业虽然并不是很符合我最初的预想,但我还是成就感满满。在这个过程中,我所用到的所有技术几乎都是从零学起的。这是从无到有的过程,我真觉得这四十多小时,我学到的东西比以前一个月的还多(以前太懒)。我学会了网页爬取数据处理,这对我今后的发展肯定是大有所益的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值