疫情数据:爬取--存取(MySQL)--绘图三步走

内容简要

人在家中坐,无聊天上来
背景:之前在不灵不灵大学学了MySQL、python等,回不去学校,也找不到工作,一直也没用的上
目的:获取疫情的所有数据信息,将数据存入数据库
意义:将存入数据库的数据用来练习Mysql和pandas的运用,以及matplotlib绘图或者pyecharts
技术路线:获取数据,简单整理,存入数据库,数据库取出数据
要求:了解requests和bs4的基本使用,熟悉python的数据结构,了解mysql的基本语法和pymysql的基本使用
收获:加深了requests和bs4的基本使用,熟悉了 爬取流程,以及数据存入的过程和出现的问题,包括数据取出遇到		
	的问题。
总结:本文主要针对简单的数据爬取和存入以及取出和绘图进行了流程介绍,其中的每个内容的具体部分不涉及,
	本次的抓取主要是为了在mysql里数据练习基本操作,所绘图也是为了绘图而绘图,而在数据分析里,每次进行
	操作必须有明确的目的。
目录:目录就不做了,内容也不多

注意:本内容设计的代码较多的是重复的,例如写入数据库,为的是,在复制运行的时候能够直接成功打到运行的目的。
参考:部分实现参考了咱们CSDN其他博主的文章,在此以以下格式表达感谢【refCSDN:文章号】

1.1 获取数据和清洗数据

主要包含了3各功能函数和1个主函数,分别是:获取页面,解析页面,提取信息和运行函数
需要一提的是在页面解析中“soup.find("script",{"id":"getAreaStat"}).get_text()”的使用,能够将script标签里的getAreaStat属性的内容全部获取出来,方便提取更多信息。
随后信息提取用到的多是列表索引和字典索引,进行嵌套列表和字典的取值。
import requests
from bs4 import BeautifulSoup
import datetime #用来记录爬取时间
# 1 定义获取HTML内容函数:向网站发送请求,从而获取整个页面的内容
def getHTMLText(url):
    r = requests.get(url)
    r.raise_for_status#获取返回状态码,若不是200会报错,更多状态码参考【refCSDN:105240877】
    r.encoding = "utf8"
    return r.text

# 2 定义解析html内容的函数,主要是获取当前需要的地区的内容
def parserPage(html):
    soup = BeautifulSoup(html,"html.parser")
    getAreaStat = soup.find("script",{"id":"getAreaStat"}).get_text()# 标签名字,标签内的属性名子({"id":"getAreaStat"} = (id=getAreaStat))获取标签内的所有内容\
    getAreaStat = getAreaStat.replace("try ",'') #掐头去尾,因为在整个文档中改内容不符合转换字典的格式
    getAreaStat = getAreaStat.replace("catch(e){}",'')#同上
    getAreaStat = getAreaStat.replace(" window.getAreaStat = ",'"window.getAreaStat":')
    getAreaStat = dict(eval(getAreaStat))
    getAreaStat = getAreaStat["window.getAreaStat"] #获取包含各省信息的列表
    return getAreaStat

# 3 定义提取省市信息函数
def getProCitLists(dictry):
    provinces = [] #存放各省信息
    cities = [] #存放各市信息
    for i in dictry:
        #提取省信息存入字典,再将字典存入列表
        provinces.append({"地区":i["provinceName"],"现存确诊":i["currentConfirmedCount"],"疑似病例":i["suspectedCount"],"累计确诊":i["confirmedCount"],"死亡":i["deadCount"],"治愈":i["curedCount"],"往日信息":i["statisticsData"],"描述":i["comment"],"信息获取时间":str(datetime.date.today()),"p_locationID":i["locationId"]})
        if i["cities"]:#部分地区不含有市信息
            for info in i["cities"]:
                #提取市信息存入字典,再将字典存入列表
                cities.append({"地区":info["cityName"],"现存确诊":info["currentConfirmedCount"],"疑似病例":info["suspectedCount"],"累计确诊":info["confirmedCount"],"死亡":info["deadCount"],"治愈":info["curedCount"],"信息获取时间":str(datetime.date.today()),"c_locationID":info["locationId"],"所属":i["provinceName"]})

    return provinces,cities

# 4 主运行函数
def main(url):
#     html = getHTMLText(url)
#     getAreaStat = parserPage(html)
#     provinces_list,cities_list = getProCitLists(getAreaStat)
#     return provinces_list,cities_list
    return getProCitLists(parserPage(getHTMLText(url)))  #上面的简写
if __name__ == "__main__":
    url = "https://3g.dxy.cn/newh5/view/pneumonia_peopleapp"
    provinces_list,cities_list = main(url)


[{'地区': '香港',
  '现存确诊': 672,
  '疑似病例': 37,
  '累计确诊': 862,
  '死亡': 4,
  '治愈': 186,
  '往日信息': 'https://file1.dxycdn.com/2020/0223/331/3398299755968040033-135.json',
  '描述': '',
  '信息获取时间': '2020-04-05',
  'p_locationID': 810000},
{}....]









[{'地区': '武汉',
  '现存确诊': 644,
  '疑似病例': 0,
  '累计确诊': 50008,
  '死亡': 2570,
  '治愈': 46794,
  '信息获取时间': '2020-04-05',
  'c_locationID': 420100,
  '所属': '湖北省'},
 ....{}]

1.2 获取往日信息存入字典

因为该信息是一个json文件链接格式,所以只需要获取到页面之后json.loads()下即可直接提取
import json
import requests
def getDictFromJson(url):
    r = requests.get(url)
    r.raise_for_status
    r.encoding = "utf8"
    # 返回的是json格式,因此只需要转换以下即可作为字典使用
    return json.loads(r.text)
olddata = []
for i in provinces_list:
    olddata.append({"p_locationID":i["p_locationID"],"往日信息":getDictFromJson(i["往日信息"])["data"]})

0

2 将cities_list数据写入Mysql

    将数据分为不同的表,之间用locationID关联(也就是邮政编码),以便进行关联操作
    通过pymysql与mysql连接,在写入之前要确认是否需要创建专一的库和表,表的字段和需要插入的数据是否一致
    建议将创建表和库与插入数据的代码分开,以防止表成功创建内容插入错误出现一系列不必要的中断
    在此提一下用到的多条信息插入的函数executemany(sql语句,列表嵌套列表或元组的多条数据)
    多次整理数据其方法一致,就不再赘述,另外,其实可以将插入等功能封装成一个类,在这里就不花时间了,因为不常用
import pymysql
# 1 创建链接
conn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123qwe",charset="utf8")
# 2 获取操作游标,用来执行sql语句
cur = conn.cursor()
# 3 执行语句
# cur.execute("create datebase getAreaStat") #创建getAreaStat数据库
# 4 选择库
cur.execute("USE getareastat")
# 5 创建表
cur.execute("""CREATE TABLE IF NOT EXISTS cities_count(
        c_locationID INT PRIMARY KEY,
           现存确诊 INT,
           疑似病例 INT,
           累计确诊 INT,
           治愈 INT,
            死亡 INT,
            所属 INT,
            信息获取时间 varchar(20) )""") 
# 6 插入数据
data = []
for i in cities_list:
    for info in provinces_list:
        if i["所属"]==info["地区"] and i["c_locationID"] > 60: #因为某些地区存在邮编为0,不符合主键,因此过滤掉邮编为0或者为个位数的信息
            data.append((i["c_locationID"],i["现存确诊"],i["疑似病例"],i["累计确诊"],i["治愈"],i["死亡"],info["p_locationID"],i["信息获取时间"]))
#     print(data)
try:
    sql = 'insert into cities_count values(%s, %s, %s,%s,%s,%s,%s,%s)'
    cur.executemany(sql, data)
    
    conn.commit()
    print('成功...')
except Exception as e:
    conn.rollback()
    print("错误信息:", e)
cur.close()
conn.close()

成功...

3 将provinces_list数据写入Mysql

import pymysql
# 1 创建链接
conn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123qwe",charset="utf8")
# 2 获取操作游标,用来执行sql语句
cur = conn.cursor()
# 3 执行语句
# cur.execute("create datebase getAreaStat") #创建getAreaStat数据库
# 4 选择库
cur.execute("USE getareastat")
# 5 创建表
cur.execute("""CREATE TABLE IF NOT EXISTS provinces_count(
        p_locationID INT PRIMARY KEY,
           现存确诊 INT,
           疑似病例 INT,
           累计确诊 INT,
           治愈 INT,
            死亡 INT,
            所属 INT,
            信息获取时间 varchar(20) )""") 
# 6 插入数据
data = []
for i in provinces_list:
    data.append((i["p_locationID"],i["现存确诊"],i["疑似病例"],i["累计确诊"],i["治愈"],i["死亡"],999999,i["信息获取时间"]))
    print(data)
try:
    sql = 'insert into provinces_count values(%s, %s, %s,%s,%s,%s,%s,%s)'
    cur.executemany(sql, data)
    
    conn.commit()
    print('成功...')
except Exception as e:
    conn.rollback()
    print("错误信息:", e)
cur.close()
conn.close()

4 将描述信息数据写入Mysql

import pymysql
# 1 创建链接
conn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123qwe",charset="utf8")
# 2 获取操作游标,用来执行sql语句
cur = conn.cursor()
# 3 执行语句
# cur.execute("create datebase getAreaStat") #创建getAreaStat数据库
# 4 选择库
cur.execute("USE getareastat")
# 5 创建表
cur.execute("""CREATE TABLE IF NOT EXISTS pcnames(
        locationID INT PRIMARY KEY,
           地区 varchar(20)
            )""") 
# 6 插入数据
data = []
for i in provinces_list:
    data.append((i["p_locationID"],i["地区"]))
for i in cities_list:
    if i["c_locationID"] > 60:
        data.append((i["c_locationID"],i["地区"]))
print(data)
try:
    sql = 'insert into pcnames values(%s, %s)'
    cur.executemany(sql, data)
    
    conn.commit()
    print('成功...')
except Exception as e:
    conn.rollback()
    print("错误信息:", e)
cur.close()
conn.close()

[(810000, '香港'), ........ , (420000, '湖北省')]
成功...

4 将往日信息写入Mysql

import pymysql
# 1 创建链接
conn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123qwe",charset="utf8")
# 2 获取操作游标,用来执行sql语句
cur = conn.cursor()
# 3 执行语句
# cur.execute("create datebase getAreaStat") #创建getAreaStat数据库
# 4 选择库
cur.execute("USE getareastat")
# # 5 创建表
# cur.execute("""CREATE TABLE IF NOT EXISTS olddata(
#         p_locationID INT,
#         confirmedCount INT,
#           confirmedIncr INT,
#           curedCount INT,
#           curedIncr INT,
#           currentConfirmedCount INT,
#           currentConfirmedIncr INT,
#           dateId varchar(20),
#           deadCount INT,
#           deadIncr INT,
#           suspectedCount INT,
#           suspectedCountIncr INT
#            )""") 
# 6 插入数据
data = []
for i in olddata:
    for info in i["往日信息"]:
        data.append((i["p_locationID"],info["confirmedCount"],info["confirmedIncr"],info["curedCount"],info["curedIncr"],info["currentConfirmedCount"],info["currentConfirmedIncr"],info["dateId"],info["deadCount"],info["deadIncr"],info["suspectedCount"],info["suspectedCountIncr"]))
#     print(data)
try:
    sql = 'insert into olddata values(%s, %s, %s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
    cur.executemany(sql, data)
    
    conn.commit()
    print('成功...')
except Exception as e:
    conn.rollback()
    print("错误信息:", e)
cur.close()
conn.close()

成功...

5 从Mysql中选取数据

import pymysql
# 1 创建链接
conn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123qwe",charset="utf8")
# 2 获取操作游标,用来执行sql语句
cur = conn.cursor()
# 3 执行语句
# cur.execute("create datebase getAreaStat") #创建getAreaStat数据库
# 4 选择库
cur.execute("USE getareastat")
cur.execute("select p_locationID,现存确诊,地区 from provinces_count p left join pcnames pc on p.p_locationID = pc.locationID where 现存确诊 >100") #执行选择语句
data = cur.fetchall()  #获取所有数据

6 将数据转为pandas

import pandas as pd
df = pd.DataFrame(data,columns = ['p_locationID','现存确诊',"地区"]).set_index("p_locationID") ##将数据读取成pd格式;设置索引列;在保存文件时,去掉索引df.to_csv(save_path, index=None)【refCSDN:82527120】
df.head()
# df.describe() #基本的统计描述一揽
现存确诊 地区
p_locationID
110000 137 北京市
310000 169 上海市
420000 648 湖北省
440000 129 广东省
710000 300 台湾
df["现存确诊"] #索引列
df.loc[420000] #索引行
现存确诊    648
Name: 420000, dtype: int64
df["现存确诊"] #索引列
df.loc[420000] #索引行
现存确诊    648
地区      湖北省
Name: 420000, dtype: object

7 从pandas读取相关数据绘图_简单例子1

#饼图
import matplotlib.pyplot as plt
import matplotlib as mat

mat.rcParams["font.family"]='STSong'  #此类设置会改变所有的文本配置,设置成中文
mat.rcParams['font.size']=15
a
plt.pie(df["现存确诊"],labels = df["地区"],autopct = "%0.1f%%",shadow = False,startangle=900)
plt.show()
# plt.xlabel("横轴名:横轴标题",fontproperties = "SimHei",fontsize = 15)或者此种方法只改变当前的文本配置

疫情数据:爬取--存取(MySQL)--绘图三步走_第1张图片

7 从pandas读取相关数据绘图_简单例子2

# 与例子1重复

import pymysql
# 1 创建链接
conn=pymysql.connect(host="127.0.0.1",port=3306,user="root",password="123qwe",charset="utf8")
# 2 获取操作游标,用来执行sql语句
cur = conn.cursor()
# 3 执行语句
# cur.execute("create datebase getAreaStat") #创建getAreaStat数据库
# 4 选择库
cur.execute("USE getareastat")
cur.execute("select p_locationID,现存确诊,地区 from provinces_count p left join pcnames pc on p.p_locationID = pc.locationID") #执行选择语句
data = cur.fetchall()  #获取所有数据
# 与例子1重复
import pandas as pd
df = pd.DataFrame(data,columns = ['p_locationID','现存确诊',"地区"]).set_index("p_locationID") ##将数据读取成pd格式;设置索引列;在保存文件时,去掉索引df.to_csv(save_path, index=None)【refCSDN:82527120】
df.head()
# df.describe() #基本的统计描述一揽
现存确诊 地区
p_locationID
110000 137 北京市
120000 33 天津市
130000 11 河北省
140000 5 山西省
150000 42 内蒙古自治区

import matplotlib.pyplot as plt
import numpy as np
import pylab
import matplotlib 

matplotlib.rcParams["font.family"] = "SimHei" #显示中文
index_ls = list(df["地区"])  #要在x轴刻度显示的文本标签内容

plt.bar([i for i in range(len(index_ls))], df["现存确诊"])
plt.xticks([i for i in range(len(index_ls))],index_ls) ## 可以设置坐标字
plt.title('This is a title')
plt.xticks(fontsize=5)  #设置坐标轴刻度字体大小 【refCSDN:60478927】
pylab.xticks(rotation=60)  #设置坐标轴文本的旋转方向【refCSDN:78927283】
plt.savefig("D:/pick/test_1",dpi = 600) #保存为png文件,dpi是指每英寸里包含点的数量,600相对较高了,png是默认

plt.show()

疫情数据:爬取--存取(MySQL)--绘图三步走_第2张图片

你可能感兴趣的:(python)