疫情數據爬取及數據可視化


新型冠狀病毒來襲,在此全國人民齊心抗疫之際,身為軟件工程專業的一員,也要充分發揮專業能力,為疫情做點什么。

到目前為止,很多網站或者APP都新增了疫情數據分析這樣一個欄目,這樣一個專欄幫助用戶充分了解全國各地乃至全世界的疫情情況,今天就特地做了這樣的一個實戰項目,來實現疫情數據的實時可視化。

首先,設計思路如下:

(1)使用爬蟲爬取網站中的數據並存入數據庫

(2)使用java做后端將數據庫的內容傳送到前端

(3)前端使用echarts框架對數據進行可視化

在爬取數據的時候,還是經歷了一些小插曲,我爬取的網站如下:

https://news.qq.com/zt2020/page/feiyan.htm#/

首先就是按照爬蟲套路查看網頁源代碼,可以看到效果如下:

 

 

很容易發現,class為areaBox的 tr 標簽中保存的是各省的數據,其中的area為省份名稱,其余不包含class的 td保存的是疫情的各項人數,而class為 city 的tr中保存的是各個城市的數據,其中,area為城市名稱,其余td保存的疫情各項的人數。

在這樣的簡單分析之后,頓時感覺這實在是太小兒科了,兩個嵌套for循環就可以搞定,於是開始編寫爬蟲,初始測試爬蟲代碼如下:

import requests
from bs4 import BeautifulSoup

url = "https://news.qq.com/zt2020/page/feiyan.htm#/"
r = requests.get(url)

html = r.text
soup = BeautifulSoup(html,"lxml")
print(soup.prettify())

運行之后,打印數據是這樣的

 

只有一坨 js 代碼還有頁面頭部的幾個div,並沒有找到我們想要的標簽。遲疑了一瞬間,恍然醒悟數據應該是通過js發送請求之后從后台傳回來的。直接看這一段HTML代碼,果然什么都看不出來。沒辦法,F12去瀏覽器控制台看看到底發生了什么數據交換的操作吧。(微軟的瀏覽器用的有點雞肋,這里切一下Chrome)可以看到服務器返回了這些數據:

 

可以看到除了無關緊要的png圖片等資源,還返回了這樣一堆js文件,一看名字,這些get***Info可能就是我們需要的,檢查一下它的地址,然后復制打開

 

 

瞬間激動了有木有!!這不就是現成的json數據么,還分析個球的HTML標簽,直接爬起來!!!

(激動過頭了)先分析一下json的格式和我們需要的“樹”,首先可以看到開頭有個name 中國的字樣,由於該網站支持其他國家的數據,如下:

 

所以我們解析json的時候就要通過它來篩選本國的數據,那么,在中國下面,又有這樣一些數據:

 

很顯然,在name的子數據中,key為children的數據就是對應的各省份的數據(其他省份格式相同,不再給出截圖),與此同時,在省份下面的各個城市,同樣是以children標簽保存數據的

 

 

以武漢為例,today中是今日新增的確診,total中是截止到目前的總人數,也是我們需要的數據,簡單翻譯可知,confirm為確診人數,dead為死亡人數,heal為治愈人數,那么數據的更新時間在哪兒呢?json開頭我們可以看到這樣的字樣:

 

在該文件的其余地方均沒有類似時間字樣的key,不難推斷出,它就是最新的數據更新時間。

OK,到此為止,分析完成,代碼搞起來!

import requests
import json
from pymysql import *

#連接數據庫的方法
def connectDB():
    try:
        db=connect(host='localhost',port=3306,user='root',password='010218',db='payiqing_db')
        print("數據庫連接成功")
        return db
    except Exception as e:
        print(e)
    return NULL

db=connectDB()

#向數據庫中插入數據的方法
def insertInformation(db,table,Date,Province,City,Confirmed_num,Yisi_num,Cured_num,Dead_num,Code):
    cursor=db.cursor()
    try:
        cursor.execute("insert into %s(Date,Province,City,Confirmed_num,Yisi_num,Cured_num,Dead_num,Code) values('%s','%s','%s','%s','%s','%s','%s','%s')" % (table,Date,Province,City,Confirmed_num,Yisi_num,Cured_num,Dead_num,Code))
        print("插入成功")
        db.commit()
        cursor.close()
        return True
    except Exception as e:
        print(e)
        db.rollback()
    return False

def queryInformation(city):
    cursor = db.cursor()
    sql = "SELECT * FROM info WHERE City =  '%s'" % (city)
    try:
        # print(sql)
        # 執行SQL語句
        cursor.execute(sql)
        # 獲取所有記錄列表
        results = cursor.fetchone()
        return results[-1]
    except Exception as e:
        print(e)
        db.rollback()

def clearTable(date):
    cursor = db.cursor()
    sql="delete from info2 where Date = '%s'"% (date)
    try:
        print(sql)
        # 執行SQL語句
        cursor.execute(sql)
    except Exception as e:
        print(e)
        db.rollback()

def get_data():
    url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5'
    json_text = requests.get(url).json()
    data = json.loads(json_text['data'])
    update_time = data['lastUpdateTime']
    all_counties = data['areaTree']
    all_list = []
    for country_data in all_counties:
        if country_data['name'] == '中國':
            all_provinces = country_data['children']
            for province_data in all_provinces:
                province_name = province_data['name']
                all_cities = province_data['children']
                for city_data in all_cities:
                    city_name = city_data['name']
                    city_total = city_data['total']
                    province_result = {'province': province_name, 'city': city_name,'update_time': update_time}
                    province_result.update(city_total)
                    all_list.append(province_result)

    clearTable(all_list[0].get("update_time"))
    for info in all_list:
        print(info)
        insertInformation(db,"info2",info.get("update_time"),info.get("province"),info.get("city"),info.get("confirm"),info.get("suspect"),info.get("heal"),info.get("dead"),queryInformation(info.get("city")))



if __name__ == '__main__':
    get_data()

以上代碼包含數據庫的更新,讀者可根據自己數據庫的配置自行修改。

然后就是數據可視化了,這里只給出截圖吧,完整代碼后續會上傳到我的GitHub中。

 

最后,附上實現本次項目的PSP表格

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM