2020,努力做一个无可替代的人!如果我写的早一点,先说明一下,这是一篇爬虫+分析+自动化的文章,不是上一节说的NumPy系列。NumPy系列的下一节敬请期待。这篇实战文章也是心血来潮,简单说一下:自从疫情爆发以来,每天早上第一件事就是关注微博热搜中各地确诊病例数的消息.不得不说,真的很感人,前几天突然涨1w+有点吓人,幸好这几天降了。这几天照例上热搜,发现关于确诊病例数的新闻并没有上热搜,有时要找相关数据要好一阵子。好吧,既然这样,那我们就自己写个程序,自己更新数据吧。大概这篇文章的由来是这样的,心血来潮,就有了。好了,这篇介绍的背景说完了,说说这篇文章:技术方面:爬虫+数据库+数据处理+绘图+邮件相关技术一看就会用到,技术点还是蛮多的。如果你经常看公众号的文章,你会发现大部分的知识点都被专门写过了。我会一一列出。如果您不理解文章的哪一部分,请在继续之前返回并查看它。爬虫:动态获取数据,BeautifulSoup详解Database:数据库存储email:Email发送文本我们想做一个自动化的程序,当然不仅仅是一个爬虫那么容易。首先明确需求:爬虫获取最新的疫情数据,简单清洗数据,保存数据库,绘制热力图,与前一天的数据进行对比,将结果以邮件的形式发送。程序每天的定时执行大概就是以上五个步骤,并不难。.绘制热图是一门新知识,可能需要一些时间来准备,让我们开始吧!爬取数据首先要确定数据源,这个很简单。说句题外话,这次疫情期间,感觉官媒还是很厉害的。数据可在第一时间公开发布,让公众知晓。还是很给力的,包括国家卫健委、人民日报、丁香园、百度地图等等,都有最新的数据。就不一一列举了,网上都能找到。这个爬虫我用的是丁香园的数据。题外话,别用那些恶意爬虫去搞这些网站,尤其是最近。谨慎看一下丁香园官方疫情网站,可以看到有一些(国内)数据文章首发:公众号“知秋小萌”文章首发:公众号“知秋小萌”一篇是该地区累计确诊病例数一个是当前最新的数据,当然还有很多折线图。我没剪。我们需要的是每个省、地、市每天的相关数据。查看源码,可以看到:文章第一贴:公众号《知秋小萌》里面有三个div需要注意:divofclass='fold\\\_xVOZX':所有数据(总计)ofeachprovinceclass='areaBlock1\\\_3V3UU'的div:各省的汇总数据(分)thedivofclass='areaBlock2\\\_27vn7':各省所有地市的数据(分))我们需要的数据在这三个div里面,我们看看div里面有什么:第一篇:公众号《知秋小萌》红色是省的汇总数据,黄色是地市的数据,黑色为具体数据标签。省份汇总数据的div和城市数据的div下面分别有5个p标签存放数据,基本相同。5个p标签为:class='subBlock1\\\_j0DGa'p标签:表示省/市名称class='subBlock2\\\_E7-fW':表示现有确诊病例数;p标签表示确诊病例数class='subBlock4\\\_ANk6l':表示累计确诊数;人数类的p标签='subBlock5\\\_2EkOU':表示治愈人数的数据足够了。选择一种爬虫方式向下爬取并打开页面。我的第一感觉是动态数据。如果你不相信我,你也可以试试selenium。数据爬取,我尝试贴出核心代码,文末也有获取源码的方法#初始化seleniumexecutable_path="你本地的chromedriver.exe路径"#设置不弹窗显示chrome_options=Options()chrome_options.add_argument('--headless')chrome_options.add_argument('--disable-gpu')browser=webdriver.Chrome(chrome_options=chrome_options,executable_path=executable_path)也可以选择的弹窗显示selenium,源代码中也有写。browser.get(url)#输出网页源代码content=browser.page_sourcesoup=BeautifulSoup(content,'html.parser')#获取中国城市疫情数量soup_city_class=soup.find('div',class_='areaBox___3jZkr').find_all('div',class_='areaBlock2___27vn7')#获取每个城市的数据#循环省略resolve_info(per_city,'city')#获取中国省份的疫情数量soup_province_class=soup.find('div',class_='areaBox___3jZkr').find_all('div',class_='areaBlock1___3V3UU')#获取各省的数据#循环省略resolve_info(per_province,'province')循环获取各省的code和每个城市我没写,你只要知道per\_city和per\_province代表每个城市和省。在解析函数中,直接获取我们需要的几个数据#解析省市的详细数据iftag=='city':#Citydata_name=data.find('p',class_='subBlock1___j0DGa').find('span').stringelse:#省份data_name=[stringforstringindata.find('p',class_='subBlock1___j0DGa').strings][0]#现有确诊病例数data_curr_diagnose=data.find('p',class_='subBlock2___E7-fW').string#累计确诊病例数data_sum_diagnose=data.find('p',class_='subBlock4___ANk6l').string#死亡人数data_death=data.find('p',class_='subBlock3___3mcDz').string#固化数data_cure=data.find('p',class_='subBlock5___2EkOU').string当然也会有一些特殊情况,比如:有些省份在bottom,有些数据是空的等等,合理处理就好了。第一篇:公众号《知秋小萌》好了,所有的数据都拿到了,爬虫就结束了。数据清洗拿到数据后,大致看了一眼,比较有规律。在数据中,我找到了两个需要处理的地方。数据中有空值。有些城市名称实际上并不是城市的名称。以北京为例,看数据:第一篇:公众号『知秋小萌』Huang颜色标注缺失数据,红色为异常名称。我是这样处理的:第一处:官网上的数据没有0,所有的空值都是0,直接填就可以了。第二处:部分数据名称错误,可以看源码根据需要删除或合并到首都城市:drop(index=df_data[df_data['city']=='待指定区域'].index,axis=1,inplace=True)#df_data.drop(df_data['city']=='来北京的人来自外地的',axis=1,inplace=True)#df_data.drop(df_data['city']=='外地来上海的人',axis=1,inplace=True)#df_data.drop(df_data['city']=='外地来天津的人',axis=1,inplace=True)#将空记录填为0df_data.fillna(0,inplace=True)#添加日期字段df_data['date']=time_str代码应该看得懂,就不解释了。日期字段是为了方便取出这两天的数据对比之后,接下来就是将数据导入数据库。一共有两张表,省数据表和市数据表。看一下数据库表结构:第一篇:公众号《知秋小萌》省表类似,只是城市名换成了省名。当然,如果你觉得两张表麻烦,一张表也能存这些数据,看你的了。对于我们DataFrame类型的数据,直接一行代码导入数据库就可以了。好看#连接数据库connect=create_engine('mysql+pymysql://username:passwd@localhost:3306/db_name?charset=utf8')#保存数据到数据库df_data.to_sql(name=table_name,con=connect,index=False,if_exists='append')你不觉得连接数据库算一行吗?然后两行,给大哥下跪,数据搞定。让我们开始绘制数据。我们要绘制的是热力图。直接使用pyecharts。时间,更容易上手这里需要安装两个模块,pyecharts和pyecharts,用于绘制图片并输出为图片保存安装。直接在cmd下输入pipinstall模块名。《知秋小萌》如果模块包安装没有问题,可以画图#导入对应模块frompyechartsimportoptionsasoptsfrompyecharts.chartsimportMapfrompyecharts.renderimportmake_snapshotfromsnapshot_seleniumimportsnapshot"""绘制热力图"""#获取数据list_data=df_data.iloc[:,[1,3]].values.tolist()#绘制热力图ncp_map=(Map(init_opts=opts.InitOpts('1000px','600px')).add('',list_data,'china').set_global_opts(title_opts=opts.TitleOpts(title=title,pos_left='center'),ptsvisualmap_opts=opts.Visual#设置为分段数据显示is_piecewise=True,#设置拖拽的句柄is_calculable=True,#设置数据的最大值,每个自定义范围max_=df_data['sum_diagnose'].max(),以及的文本每个段落,以及每个段落的特殊样式pieces=[{'min':10001,'label':'>10000','color':'#4F040A'},{'min':1000,'max':10000,'label':'1000-10000','color':'#811C24'},{'min':500,'max':999,'label':'500-999','color':'#CB2A2F'},{'min':100,'max':499,'label':'100-499','color':'#E55A4E'},{'min':10,'max':99,'label':'10-99','color':'#F59E83'},{'min':1,'max':9,'label':'1-9','color':'#FDEBCF'},{'min':0,'max':0,'label':'0','color':'#F7F7F7'}]),))#保存图片到本地make_snapshot(snapshot,ncp_map.render(),filepath_save)看起来不错。需要说明的是,我们需要的是省/市名称+累计确诊病例数。它们对应的是第二列和第四列,所以上面的代码是这样写的df_data.iloc[:,[1,3]]还有一些地图控件的设置。明白什么意思就可以了。如果您不知道,请查看API文档。我已经一行一行地写评论了。不要说你看不懂生成的图片。来看看是什么第一篇文章的出场:公众号《知秋小萌》根据每天更新的数据,对比最近两天的增长情况,做表得到最近两天的数据库数据#设置日期data_time=datetime.now()+timedelta(-2)data_time_str=data_time.strftime('%Y-%m-%d')#获取数据库这两天的数据sql_province='select*fromt_ncp_province_infowheredate>={0}'.format(data_time_str)df_province_data=pd.read_sql_query(sql_province,connect)将数据按天分为两部分,做差值即可,直接贴代码#获取数据datedate_list=df_data['date'].drop_duplicates().values.tolist()#根据日期拆分dataframedf_data_1=df_data[df_data['date']==date_list[0]]df_data_2=df_data[df_data['date']==date_list[1]]#昨天-前天比较新数据df_data_result=df_data_2[['curr_diagnose','sum_diagnose','death','cure']]-df_data_1[['curr_diagnose','sum_diagnose','death','cure']]进一步计算数据的环比增长率#添加一列df_data_result['curr_diagnose_ratio']=(df_data_result['curr_diagnose']/df_data_1['curr_diagnose']).应用(lambdax:format(x,'.2%'))df_data_result['sum_diagnose_ratio']=(df_data_result['sum_diagnose']/df_data_1['sum_diagnose']).apply(lambdax:format(x,'.2%'))df_data_result['death_ratio']=(df_data_result['death']/df_data_1['death']).apply(lambdax:format(x,'.2%'))df_data_result['cure_ratio']=(df_data_result['cure']/df_data_1['cure']).apply(lambdax:format(x,'.2%'))如果我们要显示邮件中的表格内容,还需要排序和更改将列名按照对应的数据降序排列,这样增长变化看起来更明显sum_diagnose','sum_diagnose_ratio','curr_diagnose','curr_diagnose_ratio','死亡','death_ratio','治愈','cure_ratio']]df_data.rename(columns={tag:name,io'sum_diagnose':'accumulatednumberofconfirmedcases',diag'sum:'累计诊断链增长率','curr_diagnose':'现有确诊人数es','curr_diagnose_ratio':'现有诊断链增长率','death':'死亡人数','death_ratio':'死亡链增长率','cure':'治愈人数','cure_ratio':'治疗链增长率'},inplace=True)#数据排序df_data.sort_values(['累计确诊人数','累计确诊环比增长率'],inplace=True,ascending=False)df_data.reset_index(inplace=True)ok,以上数据,包括生成的图片是我们需要将上一步中的图片和表格数据添加到邮件中显示的待发送邮件的文本中。所以邮件的正文需要以html格式发送。而我们需要在文本中插入这两天的数据,所以我们需要在html中设置#部分html内容这样'
