1.概述

1.1 目的和意义

新型冠状病毒感染的肺炎疫情爆发后,对人们的生活产生很大的影响。当前感染人数依然在不断变化。每天国家卫健委和各大新闻媒体都会公布疫情的数据,包括累计确诊人数、现有确诊人数等,对此我们可以使用自己学习的知识进行,把网上的数据进行爬取下来时刻观测疫情的变化情况。

1.2 制作开发环境

操作系统:Windows 10
开发工具: pycharm,Fiddler
开发语言:Python

2.收集数据与软件配置

2.1 数据来源

2.1.1 初次数据进行筛选
自新冠肺炎(covid-19)疫情爆发以来,这场疫情几乎影响了每个人的生活,为了对疫情做数据分析,需要采集疫情的数据,本篇案例就基于python爬虫进行数据采集。
首先我们需要找到合适的数据源,卫健委和各媒体每天都会报道新冠肺炎的疫情数据,如下图所示,因此我们可以考虑将这些网页作为数据源。

经过我的考虑我这次的选择网易的疫情动态网站作为爬虫的主要数据源,前两个虽然也类似,但是其中一个是图片格式的不利于爬虫爬取,另一个的数据源的结构不如网易数据的清晰,这就是我选择他的原因了。
2.1.2 对网站的分析
想爬取数据就要先对整个网站进行全面化的分析才行,这里我用到了Fiddler软件,打开软件后启动浏览器
• 访问网易实时疫情播报平台(https://wp.m.163.com/163/page/news/virus_report/index.html?_nw_=1&_anw_=1)
• 讲Fiddler软件开启到捕获数据模式。 捕获方式为web浏览器。
• 重新刷新浏览器后,将会有大量的流量包被捕获。
• 筛选流量包其中就有我们需要的url地址。

URL=https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=318458592046
这里我们发现URL是一个JSON格式的API网页数据,所以我们直接调用API就好了,无需再用什么正则表达式、BS4等刷选工具进行数据筛选了。
注释:Fiddler是一个http调试代理,它能 够记录所有的你电脑和互联网之间的http通讯,Fiddler 可以也可以让你检查所有的http通讯,设置断点,以及Fiddle 所有的“进出”的数据(指cookie,html,js,css等文件,这些都可以让你胡乱修改的意思)。 Fiddler 要比其他的网络调试器要更加简单,因为它仅仅暴露http通讯还有提供一个用户友好的格式。

已经找到我们需要的url地址了,这个时候我还需要看一下他的头信息,以后用来做反扒措施。其实网易对这个网站对爬取还是比较友好的。几乎是没有什么反扒措施。但是以防万一养成良好的习惯该做的还是要加上的。这里我们只弄一个user-Agrnt就可以了。

2.2 Pycharm软件的配置

2.2.1 Scrapy框架
Scrapy框架是一个python的爬虫框架,使用Scrapy可以提高开发效率,并且非常适合做一些中大型爬虫项目。 简单来说,urllib库更适合写爬虫文件,scrapy更适合做爬虫项目。
一、 安装所需要的组件
首先更新pip python -m pip install--upgrade pip
安装 whell
安装 lxml
安装 Twisted
安装 scrapy pip install scrapy

这里比较基础我就不过多的阐述了,更多了解请访问 www.baidu.com

2.2.2 Scrapy各个文件的介绍

  1. Scrapy Engine(引擎):Scrapy框架的核心部分。负责在Spider和ItemPipeline、Downloader、Scheduler中间通信、传递数据等。
  2. Spider(爬虫):发送需要爬取的连接给引擎,最后引擎吧其他模块请求回来的数据再发送给爬虫,爬虫就去解析想要的数据。//这个部分是我们开发者自己去写的,因为要爬取哪些连接,页面中的那些数据是我们需要的,都是程序员自己来决定的。
  3. Scheduler(调度器):负责接收引擎发送过来的请求,并按照一定的方式进行排列和整理,负责调度请求的顺序等。
  4. Downloader(下载器):负责接收引擎发送过来的下载请求,然后去网络下载对应的数据再交还给引擎。
  5. Item Pipeline(管道):负责将Spider(爬虫)传递过来的数据进行保存。具体保存在哪里,应看开发者的具体自己的需求。

6.Downloader Middlewares(下载中简件):可以扩展引擎和爬虫之间通信功能的中间件。
2.3 注意事项
注意:在ubuntu上安装scrapy之前,需要先安装一下依赖:
Sudo apt-get install python-dev python-pip libxml12 -dev libxslt1-dev zliblg-dev libffi-dev libssl-dev

再通过pip install scrapy安装。

如果再windows下提示没有win32api 那么你需要安装 pip install pypiwin32

3.疫情爬取代码详解

3.1 scary代码开头模板

写代码之前我们需要

创建一个爬虫 进入到项目所在的路径创建
scrapy genspider [爬虫文件名字] [网址域名]
scrapy genspider -l 查看所有爬虫模板
scrapy genspider -t [模块名字] [爬虫文件名字] [网址域名]
这里我先创建一个scrapy模板
在本地的D:\1学习\python项目\crawl目录下启用cmd 输入scrapy genspider yqsj2 www. wp.m.163.com就会创建一个默认端模板

3.2 实时数据爬取

3.2.1全国各省实时数据爬取

爬取之前我们将setting文件进行配置, 改为FALSE这样防止网站有robotstxt协议让我们爬取不了,

将headers文件也要填写上,格式是键值对的格式。
因为我需要使用管道文件,所以将注释的pipelines文件也要解开。

然后我们抓取全国各省的实时数据,在areaTree键值对中,存放着世界各地的实时数据,areaTree是一个列表,每一个元素都是一个国家的数据,每一个元素的children是各国家省份的数据。 我们首先找到中国各省的实时数据,其实中国各省的实时数据就在,下图 data-areatree-2-children

主函数里面name就是你的爬虫文件名字
allowed_domains = ['c.m.163.com']说明你只能怕这个网站下面的url连接别的都不可以爬取。这样有助于防止爬错数据。
Start_urls是一个初始的url代码池是一个数组,里面可以存放多个初始连接,这里的连接后面会进行请求后传输给parse函数进行解析。

def parse(self, response):#解析数据
parse 里面是response可以将call里面的开始url池里的代码接收到此函数里面进行处理

我将数据的调用处理用类封装了起来,通过调用函数的方式将数据进行处理,并通过item[‘文件名’] 将数据存储在了item里面

Item文件就是按照固定的格式进行进行定义成一个类似于字段的存储容器。

1.    data_province=Fssj.father_fun(self,json_data=json_data)#中国省的实时数据1  
2.    item['ChineseDATA']=Fssj.chinese_city(self,data_province=data_province)#中国省的实时数据2  

    #当前中国各个省的实时数据  
    class Fssj:  
        def father_fun(self,json_data):  
            data=json_data['data']  
            #data_son1 = json_data['data']  
            data_province = data['areaTree'][2]['children'] #中国下面的所以省份信息。  
            data_province[0].keys()#查看当前下面的列表有什么键名。  
            return data_province  
       #遍历中国的所有省的  
        def chinese_city(self,data_province):  
            info = pandas.DataFrame(data_province)[['id', 'lastUpdateTime', 'name']]#主信息  
            today_data = pandas.DataFrame([province['today'] for province in data_province])  
            total_data = pandas.DataFrame([province['total'] for province in data_province])  
            total_data.columns = ['total_' + i for i in total_data.columns]#设置列名称  
            today_data.columns = ['today_' + i for i in today_data.columns]  
            return pandas.concat([info,today_data,total_data], axis=1)  

数据处理完了后我们还需要干什么呢,对!那就是存储了
存储我们只需要调用item容器然后将他保存成csv格式就可以了,是不是很简单呢。贴出代码!!!
这个代码,因为要多次调用保存的缘故,我灵机一动何不封装成函数呢,用起来美滋滋,还减少了代码量。



class storage:#storange存储  
      
        def storage(self,filename,item_name,item):  
            item=item  
            file_name1 = filename + time.strftime('%Y_%m_%d', time.localtime(time.time())) + '.csv'  
            item[item_name].to_csv(file_name1, index=None, encoding='utf_8_sig')  
            print(file_name1 + ' 保存成功!')  
      
      
      
    #存储类  
    class EpidemicPipeline(object):  
        def process_item(self, item, spider):  
            #全国实时数据(省)  
            storage.storage(self,filename='全国实时数_',item_name='ChineseDATA',item=item)  
 


3.2.2全世界各省实时数据爬取
之前已经了解到在json数据data中的areaTree是列表格式,每个元素都是一个国家的实时数据,每个元素的children是各国家省份的数据,现在我们提取世界各国实时数据。你知道这意味着什么吗?对!上一级就是全世界的数据呀。
WorlDwide=scrapy.Field()#全世界的数据(国) 这个就是itmes数据是不是很眼熟呢?其实上面我已经给你拿出一次过了。

这个就是主函数的调用函数代码
item['WorlDwide']=Worldwide.data_selection(self,json_data)#全世界的实时数据
上面调用的就是这个代码:

    #全世界实时数据。  
    class Worldwide:  
       def data_selection(self,json_data):#数据位置的定位  
            data_category=json_data['data']['areaTree']#这个就是全世界的信息列表  
            print(len(data_category))  
            info = pandas.DataFrame(data_category)  
            info=info[['id','lastUpdateTime','name']]  
            info=pandas.DataFrame(data_category)[['id', 'lastUpdateTime', 'name']]  
            today_data=pandas.DataFrame([category['today'] for category in data_category])#各国下面的today(今天)数据  
            total_data = pandas.DataFrame([category['total'] for category in data_category])#各国下面的total(总)数据  
            #由于今日数据的列名于总数据的列名相同,这里将会遍历数据给每个列名添加头部名称。  
            today_data.columns=['today_'+i for i in today_data.columns]  
            total_data.columns=['total_'+i for i in total_data.columns]  
            return pandas.concat([info,today_data,total_data],axis=1) 

存储的话就不用我说了吧。就是下面那一行调用的还是上面说的封装函数。

3.3 历史数据

3.3.1 全国历史数据

pandas.concat是合并函数理解明白这个意思就好。
调用函数:

  1. item['Chinese_historical_data']=historical_data.Nationwide_historical_data(self,json_data=json_data)#全国历史数据

创建的函数:

      def Nationwide_historical_data(self,json_data):#全国历史数据  
        chinaDayList = json_data['data']['chinaDayList']  
        info=pandas.DataFrame(chinaDayList)[['date','lastUpdateTime']]#时间列  
        today_data = pandas.DataFrame([province['today'] for province in chinaDayList])  
        total_data = pandas.DataFrame([province['total'] for province in chinaDayList])  
        total_data.columns = ['total_' + i for i in total_data.columns]  # 设置列名称  
        today_data.columns = ['today_' + i for i in today_data.columns]  
        return pandas.concat([info, today_data, total_data], axis=1)  

3.3.2 全国各省历史数据爬取
找到第二个数据地址https://c.m.163.com/ug/api/wuhan/app/data/list-by-area-code?areaCode=420000 ,在页面对比发现是湖北省的历史数据。
其实后面的4200就是各个省的行政代码,所以我就先取出id(id就是行政代码)然后遍历与固定的url进行合并然后通过调用返回给parse1 ,通过yield里面调用scrapy.request函数,解析完了后传输给我后面创建的parse2, 通过这个方法指定给parse2。

1.    def parse2(self, response):  
2.         item = EpidemicItem()  
3.         json_data=json.loads(response.text)  
4.         item['National_historical_data']=historical_data.Province_historical_data(self,json_data)  
5.         a=historical_data.Province_historical_data(self,json_data)  
6.         yield item['National_historical_data']  



1.    # 全国各省历史数据爬取  
2.        def Province_historical_data_url(self,json_data):#这是url  
3.            id_data=json_data['data']['areaTree'][2]['children']  
4.            id_data2 = pandas.DataFrame(id_data)[['id','name']]  
5.            # print(id_data2['id'])  
6.            list=[]  
7.            for i in id_data2['id']:  
8.                url='https://c.m.163.com/ug/api/wuhan/app/data/list-by-area-code?areaCode='+i  
9.                list.append(url)  
10.                #取出各个省的名称  
11.                name_url=[]  
12.                for name in id_data2['name']:  
13.                    name_url.append(name)  
14.                    self.name_url=name_url  
15.            return list  
16.            #名字  
17.        def Province_historical_data(self,json_data):  
18.            data=json_data['data']['list']  
19.            info=pandas.DataFrame(data)[['date']]  
20.            today_data = pandas.DataFrame([province['today'] for province in data])  
21.            total_data = pandas.DataFrame([province['total'] for province in data])  
22.            total_data.columns = ['total_' + i for i in total_data.columns]  # 设置列名称  
23.            today_data.columns = ['today_' + i for i in today_data.columns]  
24.            name=pandas.DataFrame(self.name_url)  
25.            return pandas.concat([name,info, today_data, total_data], axis=1)  


结束语
本篇案例的主要内容是新冠肺炎疫情的数据采集,首先我们寻找合适的数据源,最终选择网易的实时疫情播报平台作为数据源,然后逐步地解析找到我们需要的数据,最后通过python爬虫获得我们得到了疫情的数据,包括中国各省和世界各国的实时数据,还包括中国整体、中国各省、世界各国的历史数据。通过这样一篇数据采集的案例让同学们学习到爬虫的基本方法,掌握这些方法能够提升数据采集的能力,并且可以使用在以后的学习和工作中。
注意:因为爬虫的对象是网页上的数据,如果这些网页的数据内容有所变动可能会导致采集无效。