針對新冠肺炎疫情的Python疫情數據爬取(基於requests和pandas)

數據源選擇

將新聞媒體的播報平臺作爲數據源,以網易的疫情播報平臺爲例,如下圖所示可以看到它的數據內容非常豐富,不僅包括國內的數據還包括國外的數據,且作爲大平臺,公信度也比較高。因此我們選擇網易的疫情實時動態播報平臺作爲數據源,其地址如下:https://wp.m.163.com/163/page/news/virus_report/index.html?nw=1&anw=1

我們基於網易的實時播報平臺尋找數據,由於它是一個實時的動態平臺,因此數據一般在Network標籤下可以找到,以Chrome瀏覽器爲例展示尋找數據步驟:

  1. 訪問網易實時疫情播報平臺
  2. 在頁面任意位置右鍵點擊檢查
  3. 進入Network標籤下的XHR,此時可能會提示刷新,按下“Ctrl+R”即可
    在網頁的檢查頁面內,左下角紅框所示的部分是我們找到的數據源,基於這些地址進行爬取,我們獲取數據的目標是全國,世界各國以及全國各省的實時以及歷史數據。

在這裏插入圖片描述

初步探索

通過比對,我們發現在第二個地址中存放着關於疫情的數據,因此我們先對這個地址進行爬蟲。接下來找到其地址,點擊headers後進行查看,在url中?後邊爲參數,可以不用設置,因此我們需要請求的地址爲:https://c.m.163.com/ug/api/wuhan/app/data/list-total ,並且可以看到請求方法爲get,同時查看自己瀏覽器的user-agent,使用requests請求時,設置user-agent僞裝瀏覽器。
在這裏插入圖片描述
接下來開始請求,首先導入使用的包,使用request進行網頁請求,使用pandas保存數據。
同時設置請求頭,僞裝爲瀏覽器使用requests發起請求,查看請求狀態。

import requests
import pandas as pd
import time 
pd.set_option('max_rows',500)
url = "https://c.m.163.com/ug/api/wuhan/app/data/list-total"	# 定義要訪問的地址 
r = requests.get(url,headers={'user-agent': '填寫自己的user-agent'})	# 使用requests發起請求
print(r.status_code)	# 查看請求狀態
print(type(r.text))
print(len(r.text))

可以看到返回後的內容是一個幾十萬長度的字符串,由於字符串格式不方便進行分析,並且在網頁預覽中發現數據爲類似字典的json格式,所以我們將其轉爲json格式。

import json
data_json = json.loads(r.text)

type(data_json)

data_json.keys()

可以看出在data中存放着我們需要的數據,因此我們取出數據。

data = data_json['data'] # 取出json中的數據
data.keys()

數據中總共有四個鍵,每個鍵存儲着不同的內容:
在這裏插入圖片描述
接下來分別獲取實時數據和歷史數據。

直接上代碼了,具體不懂可以評論討論。

import requests
import pandas as pd
import time
import json

# 將提取數據的方法封裝爲函數
def get_data(data, info_list):
    info = pd.DataFrame(data)[info_list]  # 主要信息

    today_data = pd.DataFrame([i['today'] for i in data])  # 提取today的數據
    today_data.______ = ['today_' + i for i in today_data.columns]  # 修改列名 columns

    total_data = pd.DataFrame([i['total'] for i in data])  # 提取total的數據
    total_data.______ = ['total_' + i for i in total_data.columns]  # 修改列名 columns

    return pd.concat([info, total_data, today_data], axis=1)  # info、today和total橫向合併最終得到彙總的數據


def save_data(data,name): # 定義保存數據方法
    file_name = name+'_'+time.strftime('%Y_%m_%d',time.localtime(time.time()))+'.csv'
    data.to_csv(file_name,index=None,encoding='utf_8_sig')
    print(file_name+' 保存成功!')


def main():
    pd.set_option('max_rows',500)
    url = "https://c.m.163.com/ug/api/wuhan/app/data/list-total"
    headers = {'user-agent': '這裏隨便寫入一個user-agent'}
    r = requests.get(url,headers=headers)
    # print(r.status_code)
    # print(type(r.text))
    # print(len(r.text))
    data_json = json.loads(r.text)
    type(data_json)
    data_json.keys()
    data = data_json['data']  # 取出json中的數據

    # 中國各省的實時數據爬取
    data_province = data['areaTree'][2]['children']
    today_province = get_data(data_province,['id','lastUpdateTime','name'])
    save_data(today_province, 'today_province')
    # 世界各國實時數據爬取
    areaTree = data['areaTree']  # 取出areaTree
    today_world = get_data(areaTree, ['id', 'lastUpdateTime', 'name'])
    today_world.head()
    # 中國歷史數據爬取
    chinaDayList = data['chinaDayList']
    alltime_China = get_data(chinaDayList, ['date', 'lastUpdateTime'])
    save_data(alltime_China, 'alltime_China')
    # 中國各省歷史數據爬取
    start = time.time()
    for province_id in province_dict:  # 遍歷各省編號

        try:
            # 按照省編號訪問每個省的數據地址,並獲取json數據
            url_1 = 'https://c.m.163.com/ug/api/wuhan/app/data/list-by-area-code?areaCode=' + province_id
            r = requests.get(url_1, headers=headers)
            data_json = json.loads(r.text)

            # 提取各省數據,然後寫入各省名稱
            province_data = get_data(data_json['data']['list'], ['date'])
            province_data['name'] = province_dict[province_id]

            # 合併數據
            if province_id == '420000':
                alltime_province = province_data
            else:
                alltime_province = pd.DataFrame([alltime_province, province_data])

            print('-' * 20, province_dict[province_id], '成功',
                  province_data.shape, alltime_province.shape,
                  ',累計耗時:', round(time.time() - start), '-' * 20)

            # 設置延遲等待
            time.sleep(10)

        except:
            print('-' * 20, province_dict[province_id], 'wrong', '-' * 20)

    alltime_province.info()
    save_data(alltime_province, 'alltime_province')
    # 世界各國曆史數據爬取
    country_dict = {key: value for key, value in zip(today_world['id'], today_world['name'])}
    start = time.time()
    for country_id in country_dict:  # 遍歷每個國家的編號

        try:
            # 按照編號訪問每個國家的數據地址,並獲取json數據
            url_2 = 'https://c.m.163.com/ug/api/wuhan/app/data/list-by-area-code?areaCode=' + country_id
            r = requests.get(url_2, headers=headers)
            json_data = json.loads(r.text)

            # 生成每個國家的數據
            country_data = get_data(json_data['data']['list'], ['date'])
            country_data['name'] = country_dict[country_id]

            # 數據疊加
            if country_id == '9577772':
                alltime_world = country_data
            else:
                alltime_world = pd.DataFrame([alltime_world, country_data])

            print('-' * 20, country_dict[country_id], '成功', country_data.shape, alltime_world.shape,
                  ',累計耗時:', round(time.time() - start), '-' * 20)

            time.sleep(10)

        except:
            print('-' * 20, country_dict[country_id], 'wrong', '-' * 20)

    print(alltime_world.shape)
    save_data(alltime_world, 'alltime_world')


main()

聲明:本博客內容爲學習酷客上相關案例後所做總結。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章