Python 繪製全球疫情地圖

國內疫情得到控制後,我就沒怎麼再關心過疫情,最近看到一條新聞,全球疫情累計確診人數已經突破 500w 大關,看到這個數字我還是有點吃驚的。

思來想去,還是寫一篇全球疫情的分析的文章,本文包括網絡爬蟲、全球疫情地圖繪製等方面。

網絡爬蟲

我之前有分享過疫情數據的來源,用的是 AKShare 的數據源,好用是真好用,就是網絡太慢了, AKShare 的數據很多是來源於 GitHub ,我的網絡訪問太平洋彼岸的數據還是有點力不從心。

這次我換了新的數據源,來源騰訊新聞的實時數據,站點鏈接如下:

本來我以爲需要解析頁面元素,才能獲取到數據,但是等我分析了 network 以後發現,竟然可以直接找到數據接口,這大大的方便了我們數據抓取。

獲取全球疫情數據接口如下:

https://api.inews.qq.com/newsqa/v1/automation/foreign/country/ranklist

把這個接口放在 PostMan 裏面模擬訪問一下:

毫無反爬手段,header 神馬的都不需要配置,直接訪問就能拿到數據,到這裏,我們可以開始寫爬蟲的代碼了,最終代碼如下:

import requests
from datetime import datetime

def catch_data():
    """
    抓取當前實時數據,並返回 國家、大洲、確診、疑似、死亡、治癒 列表
    :return:
    """
    url = 'https://api.inews.qq.com/newsqa/v1/automation/foreign/country/ranklist'
    data = requests.post(url).json()['data']

    date_list = list()  # 日期
    name_list = list() # 國家
    continent_list = list() # 大洲
    confirm_list = list()  # 確診
    suspect_list = list()  # 疑似
    dead_list = list()  # 死亡
    heal_list = list()  # 治癒

    for item in data:
        month, day = item['date'].split('.')
        date_list.append(datetime.strptime('2020-%s-%s' % (month, day), '%Y-%m-%d'))
        name_list.append(item['name'])
        continent_list.append(item['continent'])
        confirm_list.append(int(item['confirm']))
        suspect_list.append(int(item['suspect']))
        dead_list.append(int(item['dead']))
        heal_list.append(int(item['heal']))

    return date_list, name_list, continent_list, confirm_list, suspect_list, dead_list, heal_list


def save_csv():
    """
    將數據存入 csv 文件
    :return:
    """
    date_list, name_list, continent_list, confirm_list, suspect_list, dead_list, heal_list = catch_data()
    fw = open('2019-nCoV.csv', 'w', encoding='utf-8')
    fw.write('date,name,continent,confirm,suspect,dead,heal\n')

    i = 0
    while i < len(date_list):
        date = str(date_list[i].strftime("%Y-%m-%d"))
        fw.write(date + ',' + str(name_list[i]) + ',' + str(continent_list[i]) + ',' + str(confirm_list[i]) + ',' + str(suspect_list[i]) + ',' + str(dead_list[i]) + ',' + str(heal_list[i]) + '\n')
        i = i + 1
    else:
        print("csv 寫入完成")
        fw.close()


if __name__ == '__main__':
    save_csv()

最終得到的 csv 文件是這樣的:

全球疫情地圖

前端或網站開發的朋友應該都使用過強大的 Echarts 插件。 ECharts 是一個純 Javascript 的圖表庫,可以流暢的運行在 PC 和移動設備上,兼容當前絕大部分瀏覽器,底層依賴輕量級的 Canvas 類庫 ZRender ,提供直觀、生動、可交互、可高度個性化定製的數據可視化圖表。 ECharts 提供了常規的折線圖、柱狀圖、散點圖、餅圖、K線圖,用於統計的盒形圖,用於地理數據可視化的地圖、熱力圖、線圖,用於關係數據可視化的關係圖、treemap,多維數據可視化的平行座標,還有用於 BI 的漏斗圖、儀表盤,並且支持圖與圖之間的混搭。

既然 Echarts 如此強大, Python 肯定有相應的第三方擴展包支持,它就是我們接下來繪製世界地圖要用到的 PyEcharts 。 PyEcharts 是一個用於生成 Echarts 圖表的類庫,即 Echarts 與 Python 的對接。

安裝語句如下:

pip install pyecharts

PyEcharts 安裝完成後我們就可以開始寫接下來的代碼了,如下:

from pyecharts import options as opts
from pyecharts.charts import Map
import pandas as pd
import namemap

def read_country_code():
    """
    獲取國家中英文字典
    :return:
    """
    country_dict = {}
    for key, val in namemap.nameMap.items():  # 將 nameMap 列表裏面鍵值互換
        country_dict[val] = key
    return country_dict

def read_csv():
    """
    讀取數據,返回國家英文名稱列表和累計確診數列表
    :return:
    """
    country_dict = read_country_code()
    data = pd.read_csv("2019-nCoV.csv", index_col=False)

    countrys_names = list()
    confirmed_count = list()

    for x in range(len(data.index)):
        if data['name'].iloc[x] in country_dict.keys():
            countrys_names.append(country_dict[data['name'].iloc[x]])
            confirmed_count.append(data['confirm'].iloc[x])
        else:
            print(data['name'].iloc[x])

    return countrys_names, confirmed_count


def draw_map():
    """
    繪製世界地圖
    遇到一個很神奇的問題:
    兩個列表必須寫死數據地圖纔會渲染數據,如果數據是從方法中獲得,則地圖不渲染數據
    :return:
    """

    # countrys_names, confirmed_count = read_csv()
    # print(countrys_names)
    # print(confirmed_count)

    countrys_names = ['United States', 'Brazil', 'Russia'...]

    confirmed_count = [1666828, 347398, 335882...]


    c = (
        Map()
        .add(
            "確診人數",
            [list(z) for z in zip(countrys_names, confirmed_count)],
            is_map_symbol_show=False,
            maptype="world",
            label_opts=opts.LabelOpts(is_show=False),
            itemstyle_opts=opts.ItemStyleOpts(color="rgb(49,60,72)")
        )
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="全球 2019-nCoV 地圖"),
            visualmap_opts=opts.VisualMapOpts(max_=1700000),
        )
        .render("map_world.html")
    )


if __name__ == '__main__':
    draw_map()

最終結果如下:

在繪製全球疫情地圖的時候,我們最終使用的國家的名稱是英文的,所以需要用到一箇中英文國家名稱對照字典,這個字典我找到了兩個版本,一個是 Python 格式的文件 namemap.py ,還有一個是 json 格式的文件 country-code.json , 使用這兩個文件中的任意一個將我們在前面獲取到的數據中的中文國家名稱轉換爲英文。這兩個文件我都會提交到代碼倉庫,有需要的同學可以在公衆號裏回覆關鍵字獲取。

另外,在最後繪製地圖的時候遇到了一個很奇葩的問題,國家名稱列表和累計確診人數列表如果是從前面的方法中獲取到的,在最後渲染成 map_world.html 的時候,將不會渲染數字,所有的數字都是 null ,但是如果這兩個列表 copy 出來,寫死在代碼中,就可以成功的渲染,有清楚這個問題的朋友可以在留言中解答一下,萬分感激。

需要源代碼的同學可以在公衆號後臺回覆「全球疫情」獲取。

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