全國疫情和福建省疫情爬蟲


一.主題式網絡爬蟲設計方案

  1.主題式網絡爬蟲名稱:全國疫情累計及福建省疫情爬蟲

  2.主題式網絡爬蟲爬取的內容與特征分析:

    a.內容:全國疫情爬蟲的內容為截至目前的各省的累計確診,累計治愈,累計死亡數據,福建省疫情爬蟲為1月22日至4月22日的每日新增確診,每日新增疑似,每日新增境外輸入確診,每日境外輸入疑似數據。

    b.特征分析:全國疫情爬蟲的數據特征分析,全國疫情數據的內容為json格式,可以通過字典的形式進行訪問,福建省疫情數據為每日發布,通過html頁面獲得,多為數據格式不統一

  3.主題式網絡爬蟲設計方案概述:

    首先確定網址,以便於確定數據的來源,全國疫情數據選擇網址為(https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=316578012887), 福建省疫情數據選擇為(http://wjw.fujian.gov.cn/was5/web/search?)全國疫情網站不需要向服務器提交數據,福    建省疫情網站需要像網站提交數據。全國疫情數據返回的是一個json文件,將獲得到的文件內容保存,之后通過字典的訪問形式獲得對應數據。福建省疫情數據返回的是包含了子網頁的網址,將子網址的網址通過正則表達式匹配出來,之后進行訪問,該網站采取    的是XHR加載網頁,所以通過向服務器提交數據以便於獲得數據。

二.主題頁面的結構特征分析

  A.全國疫情數據

      

   B福建省疫情信息

 

 

    

  

    

  三.網絡爬蟲設計

from bs4 import BeautifulSoup  #導入beautifulsoup用來解析網頁
import requests #導入requests用於網頁訪問
import matplotlib.pyplot as plt #對數據畫圖,散點圖,柱狀圖等
import re #正則表達式用來匹配文章內容,過濾信息
import pandas as pd #修改格式,寫入excel
import json #json文件獲取


plt.rcParams['font.sans-serif'] = ['SimHei']  # 用來正常顯示中文標簽
plt.rcParams['axes.unicode_minus'] = False  # 用來正常顯示負號

def GetPage():# 獲取網頁源碼
    urllist = [] #保存匹配出來的網址
    for i in range(1,7):
        URL = 'http://wjw.fujian.gov.cn/was5/web/search?'  # 目標網頁地址
        formdata = {
                    "sortfield": "-docreltime,-docorderpri,-docorder",
                    "templet": "docs.jsp",
                    "channelid": "285300",
                    "classsql": "chnlid=38586",
                    "prepage": "20",
                    "page": i,
                    "r": "0.2607847720437618"
                    } #post數據
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome / 53.0.2785.143Safari / 537.36',
            'Connection': 'keep-alive',
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Cookie': '_gscu_1005022938=86859196iyievf18; _gscbrs_1005022938=1'
        }
        html = requests.post(URL, data=formdata,headers=header)  # 獲取網頁源碼
        html.raise_for_status()
        p = re.compile(r'"url":"(http.*?)"') #正則匹配出跳轉網址
        temp = re.findall(p,html.content.decode('UTF-8')) #匹配
        urllist+=temp #保存跳轉網址
    for i in urllist: #輸出網址
        print(i)
    return urllist#返回網址

def GetMsg(urllist):
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome / 53.0.2785.143Safari / 537.36',
        'Connection': 'keep-alive',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Cookie': '_gscu_1005022938=86859196iyievf18; _gscbrs_1005022938=1'
    }
    for url in urllist:
        html = requests.get(url,headers=header) #獲取網頁源碼
        soup = BeautifulSoup(html.content, 'html.parser') #使用html。parser解釋器
        f = open('word.txt', 'a', encoding='UTF-8') #寫入文件
        divs = soup.find_all('div',{'id':'detailContent'}) #匹配主要信息
        for div in divs:  #將匹配到的信息
            afont = div.find_all('font') #找到所有文字
            for font in afont: #對於每個匹配到的句子
                    str = font.text #得到文字
                    str = str.lstrip().rstrip() #去除左右空格
                    f.write(str)#寫入文件
        f.write('\n')
        f.close()
def Get_time_outland():#匹配信息
    f = open('word.txt', 'r',encoding='UTF-8') #讀入文件
    word = f.readlines()#讀入內容
    time_re = re.compile('([0-9]月[0-9]*日)')#用來匹配日期

    concern_re_outland = re.compile('新增境外輸入確診病例[0-9]*例|新增境外輸入新型冠狀病毒肺炎確診病例[0-9]*例')#匹配確診
    doubt_re_outland = re.compile('新增境外輸入疑似病例[0-9]*例|新增境外輸入新型冠狀病毒肺炎疑似病例[0-9]*例')#匹配疑似

    message_outland = {}#保存過濾出來的信息
    for str in word:#對於每句文字
        time_ = re.findall(time_re, str)#匹配日期
        num_re = re.compile('[0-9]+')#匹配數字
        concern_outland = re.findall(concern_re_outland, str)#匹配確診
        doubt_outland = re.findall(doubt_re_outland, str)#匹配疑似
        try:
            if time_[0] not in message_outland:#如果當前日期第一次出現
                message_outland[time_[0]] = [[], []]
            if len(concern_outland) <=0:#未匹配到內容
                message_outland[time_[0]][0] += '0'
            else:
                message_outland[time_[0]][0] += concern_outland#將匹配到的內容保存
            if len(doubt_outland) <= 0:
                message_outland[time_[0]][1] += '0'
            else:
                message_outland[time_[0]][1] += doubt_outland
        except:
            pass

    for time_time_, str_list in message_outland.items():#對於匹配到的信息
        for iterator in str_list:
            max_num = -1 #只需要確診或者疑似的最大數字,因為在文本中存在某市的數字
            for i in iterator:
                max_num = max(max_num, int(re.findall(num_re, i)[0]))#獲得最大數字
            message_outland[time_time_][str_list.index(iterator)]=max_num#講當日的確診疑似固定為最大數字
    return message_outland#返回數字

def Get_time_inland():#同國外
    f = open('word.txt', 'r',encoding='UTF-8')
    word = f.readlines()
    time_re = re.compile('([0-9]月[0-9]*日)')

    concern_re_inland = re.compile('新增[^境外].?.?.?.?.?.?.?.?確診病例[0-9]*例|新增.?.?.?新型冠狀病毒.?.?.?肺炎確診病例[0-9]*例')
    doubt_re_inland = re.compile('新增本地疑似病例[0-9]*例|新增.?.?.?新型冠狀病毒.?.?.?肺炎疑似病例[0-9]*例')

    message_inland = {}
    for str in word:
        time_ = re.findall(time_re, str)
        num_re = re.compile('[0-9]+')
        concern_inland = re.findall(concern_re_inland, str)
        doubt_inland = re.findall(doubt_re_inland, str)
        try:
            if time_[0] not in message_inland:
                message_inland[time_[0]] = [[], []]
            if len(concern_inland) <=0:
                message_inland[time_[0]][0] += '0'
            else:
                message_inland[time_[0]][0] += concern_inland
            if len(doubt_inland) <= 0:
                message_inland[time_[0]][1] += '0'
            else:
                message_inland[time_[0]][1] += doubt_inland
        except:
            pass
    message_inland['1月22日'][0] += '1'#最初發布信息的時候沒有准確數字,所以查看文字可知 確診一人 ,疑似為0
    message_inland['1月22日'][1] += '0'
    message_inland['1月23日'][0] += '3'#同1月22日
    message_inland['1月23日'][1] += '0'
    for time_time_, str_list in message_inland.items():
        for iterator in str_list:
            max_num = -1
            for i in iterator:
                try:
                    max_num = max(max_num, int(re.findall(num_re, i)[0]))
                except:
                    pass
            message_inland[time_time_][str_list.index(iterator)] = max_num
    return message_inland

def write_to_excel(message,mark = 1):#講內容寫進excel
    xticks = []#用來保存日期
    y1ticks = []#用來保存確診
    y2ticks = []#用來保存疑似
    for i,j in message.items():#內容格式為{日期:[確診,疑似]} 類型為字典
        xticks.append(i)#日期
        y1ticks.append(j[0])#
        y2ticks.append(j[1])
    dicts = {
        '時間':xticks,
        '新增確診':y1ticks,
        '新增疑似':y2ticks
    }
    df = pd.DataFrame(dicts)#保存到excel中
    if mark==1:
        df.to_excel('本地新增確診疑似.xlsx', index=False)
    else:
        df.to_excel('境外輸入新增確診疑似.xlsx', index=False)

def re_prope(message):#獲得累計各個市內所有確診人數
    prope_re = re.compile('..市[0-9]*例')#匹配某某市
    total_re = re.compile('累計報告本地確診病例[0-9]*例')#匹配累計確診數量
    num_re = re.compile('[0-9]*')#匹配數字
    pro_re = re.compile('..市')#匹配市
    f = open('word.txt', 'r',encoding='UTF-8')#打開文件
    word = f.readlines()#讀取文件
    for str in word:
        result = re.findall(prope_re, str)#匹配出市
        result2 = re.findall(total_re, str)#匹配累計確診
        break
    message = {}#保存清洗過后的信息
    for i in result:
        pro = re.findall(pro_re, i)#匹配市
        num = re.findall(num_re, i)#匹配數字
        if pro[0] not in message:#市第一次出現
            message[pro[0]] = 0# 先將人數置為0
        for j  in num:
            if len(j)>=1:
                j = int(j)
                message[pro[0]] = j #保存有效數字
            else:
                pass
    temp = re.findall(num_re,result2[0])#匹配數字
    for i in temp:
        if len(i)>=1:
            total = int(i)
        else:
            pass
    return message,total

def draw_fig(message):#繪制折線圖
    fig = plt.figure()#建立一個空圖
    xticks = []#x軸標簽
    y1ticks = []#y軸標簽  確診人數
    y2ticks = []#y軸標簽  疑似人數
    for i,j in message.items():#分割內容
        xticks.append(i)
        y1ticks.append(j[0])
        y2ticks.append(j[1])
    xticks.reverse()#反轉內容,因為爬取來的信息是最近日期,所以反過來
    y1ticks.reverse()
    y2ticks.reverse()
    #折線圖
    ax1 = fig.add_subplot(211)#圖分為兩部分
    plt.xlabel('時間')
    plt.ylabel('人數')
    plt.plot(xticks,y1ticks,label = '新增確診')
    plt.legend()
    plt.xticks(rotation=270)

    ax2 = fig.add_subplot(212)
    plt.xlabel('時間')
    plt.ylabel('人數')
    plt.plot(xticks, y2ticks, color='green',label = '新增疑似')
    plt.legend()
    plt.xticks(rotation=270)

    plt.savefig('福建確診疑似病例折線圖.jpg')

def draw_bar(message):#繪制柱形圖
    xvalue = []#x軸標簽
    yvalue = []#y內容
    for i,j in message.items():
        xvalue.append(i)
        yvalue.append(j)
    plt.title('各市累計確診柱形圖')
    plt.bar(xvalue, yvalue)
    plt.savefig('福建各市累計確診柱形圖.jpg')

def draw_pie(message,total_):#繪制餅圖
    total = total_#總人數
    xvalue = []
    yvalue = []
    for i, j in message.items():
        xvalue.append(i)
        yvalue.append(j)
    labels = xvalue #餅標簽
    share = []#每部分的比例
    for i in yvalue:
        share.append(i/total)
    plt.title('各市累計確診比例')
    plt.pie(share, labels=labels,autopct = '%3.1f%%',)
    plt.savefig('福建各市累計確診比例餅圖.jpg')

def nationwide():
    url="https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=316578012887"
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36'
    }
    try:
        r = requests.get(url, headers=headers) #獲取網址源碼
        r.raise_for_status()
        r.encoding = r.apparent_encoding#轉碼
        r = r.json()#轉換成json
        b = json.dumps(r,ensure_ascii=False)
        f2 = open('new_json.json','w',encoding='utf-8')
        f2.write(b)#保存數據
        f2.close()
    except Exception as e:
        print('error: ',e)
def parser_page(filename):
    f= open(filename, encoding='utf-8')#加載文件
    data = json.load(f)#讀取內容
    casedata = data['data']['areaTree'][2]['children']#獲得到國內的內容
    result = {}#保存結果
    for i in casedata:
        if i['name'] not in result:#省名字
            result[i['name']] = []
        result[i['name']].append(i['total']['confirm']) #累計確診
        result[i['name']].append(i['total']['suspect']) #現存疑似
        result[i['name']].append(i['total']['heal']) #累計治愈
        result[i['name']].append(i['total']['dead']) #累計死亡
        result[i['name']].append(i['lastUpdateTime'])#最近更新日期
    print(result)
    return result

def draw_nation_bar(data):#畫柱狀圖
    xvalue = []#x軸標簽
    y1value = []#確診人數
    y2value = []#治愈人數
    y3value = []#死亡人數
    for i,j in data.items(): #數據內容為{日期:[累計確診,現存疑似,累計治愈,累計死亡,更新日期]
        xvalue.append(i)
        y1value.append(j[0])
        y2value.append(j[2])
        y3value.append(j[3])
    fig = plt.figure() #空圖
    ax1 = fig.add_subplot(311)#分成三份
    plt.bar(xvalue[1:], y1value[1:])
    plt.title("各省累計確診(除湖北)")
    ax2 = fig.add_subplot(312)
    plt.bar(xvalue[1:], y2value[1:])
    plt.title("各省累計治愈(除湖北)")
    ax3 = fig.add_subplot(313)
    plt.bar(xvalue[1:], y3value[1:])
    plt.title("各省累計死亡(除湖北)")

    plt.savefig('各省比例.jpg')

def count_nation_pie(data): #繪制餅圖
    xvalue = []#標簽
    y1value = []#累計確診
    y2value = []#累計治愈
    y3value = []#累計死亡
    total1 = 0 #確診總數
    total2 = 0#治愈總數
    total3 = 0#死亡總數
    for i,j in data.items():
        xvalue.append(i)
        y1value.append(j[0])
        y2value.append(j[2])
        y3value.append(j[3])
        total1 += j[0]
        total2 += j[2]
        total3 += j[3]
    xvalue.remove(xvalue[0])#去除湖北, 因為湖北數據比例過大,影響直觀表現,所以去除湖北
    total1 -= y1value[0]
    total2 -= y2value[0]
    total3 -= y3value[0]
    share1 = [] #個省份的比例
    share2 = []
    share3 = []
    for i in y1value[1:]:
        share1.append(i/total1)
    for i in y2value[1:]:
        share2.append(i / total2)
    for i in y3value[1:]:
        share3.append(i / total3)
    print(xvalue, share1, share2, share3)
    return xvalue,share1,share2,share3
def draw_natiom_bar(share, labels,mark):
    fig = plt.figure()
    plt.pie(share, labels=labels, autopct='%3.1f%%')
    title = ['累計確診比例(除湖北)','累計治愈比例(除湖北)','累計死亡比例(除湖北)']
    plt.title(title[mark-1])
    plt.savefig('{}.jpg'.format(title[mark-1]))


if __name__ == '__main__':
    urllist = GetPage()
    GetMsg(urllist)
    message_inland = Get_time_inland()
    message_outland = Get_time_outland()
    draw_fig(message_inland)
    draw_fig(message_outland)
    write_to_excel(message_inland, mark=1) #寫入本地確診疑似excel
    write_to_excel(message_outland, mark=2) #寫入境外確診疑似excel
    message,total = re_prope(message_inland) #
    draw_bar(message)
    draw_pie(message,total)
    nationwide()
    data = parser_page('new_json.json')
    draw_nation_bar(data)
    x,y1,y2,y3 =  count_nation_pie(data)
    draw_natiom_bar(y1, x,1)
    draw_natiom_bar(y2, x,2)
    draw_natiom_bar(y3, x,3)

 

 

 

 程序小結:

  本程序通過post數據以獲得數據,同時也解決了爬取網址不會變化的問題,同時也實現了數據永久化的保存包括爬取下來的所有信息,通過txt文件,json文件,jpg圖像等將數據通過餅圖折線圖如柱狀圖,將數據更好的呈現出來,以便於用戶更好的獲得信息,通過獲得的這些信息,我也意識到了中國人民在面對疫情情況下的團結一心,一線工作人員的盡心竭力,這些數據的背后都是大家的努力,同時也希望大家勤洗手,多通風,不聚集,戴口罩,讓治愈數字越來越多,讓死亡和確診數字越來越少,加油福建,加油中國

 


免責聲明!

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



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