爬取疫情数据并存到mysql数据库

📋 个人简介

  • 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜
  • 📝 博主的个人网站:阿牛的博客小屋🔥
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 📣 系列专栏:python网络爬虫🍁
  • 💬格言:要成为光,因为有怕黑的人!🔥
    请添加图片描述

前言

因为我做的项目需要一些疫情数据,因此在这里总结一下数据获取以及将其保存到数据库,对网络爬虫学习者还是有帮助的。

需求分析

我们需要获取的内容是某新闻报告官网的这个国内疫情数据,包含总体数据以及各省市数据以及每天的数据及变化!

目标网站如下:https://news.qq.com/zt2020/page/feiyan.htm#/

在这里插入图片描述
如图:要获取的api有两个,第一个链接是各省市的详情数据,第二个是近30天的历史数据。

在这里插入图片描述
如图,数据是树状的,需要我们看好一层层提取,可借助json格式化工具!
最后将其保存到mysql数据库!

项目技术

爬虫-获取数据
pymysql - 连接数据库
mysql - 保存数据

数据库设计

ER图

在这里插入图片描述

建表sql

详细数据表

CREATE TABLE `details` (
  `id` int NOT NULL AUTO_INCREMENT,
  `update_time` datetime DEFAULT NULL COMMENT '数据最后更新时间',
  `province` varchar(50) DEFAULT NULL COMMENT '省',
  `city` varchar(50) DEFAULT NULL COMMENT '市',
  `confirm` int DEFAULT NULL COMMENT '累计确诊',
  `now_confirm` int DEFAULT NULL COMMENT '现有确诊',
  `confirm_add` int DEFAULT NULL COMMENT '新增确诊',
  `wzz_add` int DEFAULT NULL COMMENT '新增无症状',
  `heal` int DEFAULT NULL COMMENT '累计治愈',
  `dead` int DEFAULT NULL COMMENT '累计死亡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=528 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

历史数据表

CREATE TABLE `history` (
  `ds` datetime NOT NULL COMMENT '日期',
  `confirm` int DEFAULT NULL COMMENT '累计确诊',
  `confirm_add` int DEFAULT NULL COMMENT '当日新增确诊',
  `local_confirm` int DEFAULT NULL COMMENT '现有本土确诊',
  `local_confirm_add` int DEFAULT NULL COMMENT '本土当日新增确诊',
  `local_no_infect` int DEFAULT NULL COMMENT '现有本土无症状',
  `local_no_infect_add` int DEFAULT NULL COMMENT '本土当日新增无症状',
  `heal` int DEFAULT NULL COMMENT '累计治愈',
  `heal_add` int DEFAULT NULL COMMENT '当日新增治愈',
  `dead` int DEFAULT NULL COMMENT '累计死亡',
  `dead_add` int DEFAULT NULL COMMENT '当日新增死亡',
  PRIMARY KEY (`ds`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

pymysql连接数据库

# mysql建立连接
def get_con():
    # 建立连接
    con = pymysql.connect(host="127.0.0.1",
                          user="root",
                          password="",
                          db="",
                          charset="utf8")
    # 创建游标
    cursor = con.cursor()
    return con, cursor


# mysql关闭连接
def close_con(con, cursor):
    if cursor:
        cursor.close()
    if con:
        con.close()

password和db请配置成你的!

爬虫设计

爬虫需要模块

  • requests
  • json
  • random

因为需要多次爬取,因此我搭建了ip代理池和ua池

# ip代理池
ips = [{"HTTP": "175.42.129.105"}, {"HTTP": "121.232.148.97"}, {"HTTP": "121.232.148.72"}]
proxy = random.choice(ips)

# headers池
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'
    },
    {
        'user-agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36"
    },
    {
        'user-agent': "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:22.0) Gecko/20130328 Firefox/22.0"
    }
]
header = random.choice(headers)

爬取数据本身没有难度,数据提取比较费劲,请借助json格式化工具看清楚!

代码与展示

import traceback
import requests
import json
import time
import random
import pymysql
# ip代理池
ips = [{"HTTP": "175.42.129.105"}, {"HTTP": "121.232.148.97"}, {"HTTP": "121.232.148.72"}]
proxy = random.choice(ips)

# headers池
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'
    },
    {
        'user-agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36"
    },
    {
        'user-agent': "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:22.0) Gecko/20130328 Firefox/22.0"
    }
]
header = random.choice(headers)

# 返回历史数据和当日详细数据
def get_tencent_data():
    # 当日详情数据的url
    url1 = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=localCityNCOVDataList,diseaseh5Shelf"
    # 历史数据的url
    url2 = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=chinaDayListNew,chinaDayAddListNew&limit=30"

    r1 = requests.get(url=url1, headers=header,proxies=proxy).text
    r2 = requests.get(url=url2, headers=header,proxies=proxy).text

    # json字符串转字典
    data_all1 = json.loads(r1)['data']['diseaseh5Shelf']
    data_all2 = json.loads(r2)['data']

    # 历史数据
    history = {}
    for i in data_all2["chinaDayListNew"]:
        # 时间
        ds = i["y"] + '.' + i["date"]
        tup = time.strptime(ds, "%Y.%m.%d")  # 匹配时间  结果是时间元祖
        ds = time.strftime("%Y-%m-%d", tup)  # 改变时间输入格式,不然插入数据库会报错,数据库是datatime格式
        confirm = i["confirm"]
        local_confirm = i["localConfirm"]
        local_no_infect = i["noInfectH5"]
        heal = i["heal"]
        dead = i["dead"]
        history[ds] = {"confirm": confirm, "local_confirm": local_confirm, "local_no_infect": local_no_infect ,"heal": heal, "dead": dead}
    for i in data_all2["chinaDayAddListNew"]:
        ds = i["y"] + '.' + i["date"]
        tup = time.strptime(ds, "%Y.%m.%d")  # 匹配时间
        ds = time.strftime("%Y-%m-%d", tup)  # 改变时间输入格式,不然插入数据库会报错,数据库是datatime格式
        confirm_add = i["confirm"]
        local_confirm_add = i["localConfirmadd"]
        local_no_infect_add = i["localinfectionadd"]
        heal_add = i["heal"]
        dead_add = i["dead"]
        history[ds].update({"confirm_add": confirm_add, "local_confirm_add": local_confirm_add,"local_no_infect_add":local_no_infect_add, "heal_add": heal_add, "dead_add": dead_add})

    # 当日详细数据
    details = []
    update_time = data_all1["lastUpdateTime"]
    data_country = data_all1["areaTree"][0]
    data_province = data_country["children"]  # 中国各省
    for pro_infos in data_province:
        province = pro_infos["name"]  # 省名
        for city_infos in pro_infos["children"]:
            city = city_infos["name"]
            # 累计确珍人数
            confirm = city_infos["total"]["confirm"]
            # 现有确诊人数
            now_confime = city_infos["total"]["nowConfirm"]
            # 新增确诊人数
            confirm_add = city_infos["today"]["confirm"]
            # 新增无症状
            wzz_add = city_infos["today"]["wzz_add"]
            if wzz_add == '':
                wzz_add = 0
            else:
                wzz_add = int(wzz_add)
            # 累计治愈人数
            heal = city_infos["total"]["heal"]
            # 累计死亡人数
            dead = city_infos["total"]["dead"]
            details.append([update_time, province, city, confirm, now_confime, confirm_add,wzz_add, heal, dead])
    return history, details

# mysql建立连接
def get_con():
    # 建立连接
    con = pymysql.connect(host="127.0.0.1",
                          user="root",
                          password="",
                          db="",
                          charset="utf8")
    # 创建游标
    cursor = con.cursor()
    return con, cursor


# mysql关闭连接
def close_con(con, cursor):
    if cursor:
        cursor.close()
    if con:
        con.close()


# 插入及更新每日details数据
def update_details():
    cursor = None
    con = None
    try:
        lis = get_tencent_data()[1]  # 0是历史数据,1是当日详细数据
        con, cursor = get_con()
        sql = "insert into details (update_time,province,city,confirm,now_confirm,confirm_add,wzz_add,heal,dead) values (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
        sql_query = "select update_time from details order by id desc limit 1"
        # 执行sql语句
        cursor.execute(sql_query)
        query_data = cursor.fetchone()
        # 判断表中是否有数据以及对比当前最大时间是否相同
        # query_data[0] 中时间数据类型是datetime.datetime,li[0][0] 中时间数据类型是str
        if query_data == None or str(query_data[0]) != lis[0][0]:
            print(f"{time.asctime()} 开始更新数据")
            for item in lis:
                cursor.execute(sql, item)
            con.commit()  #提交事务
            print(f"{time.asctime()} 更新到最新数据")
        else:
            print(f"{time.asctime()} 已是最新数据!")
    except:
        #traceback模块不仅可以返回错误,还可以返回错误的具体位置
        traceback.print_exc()
    finally:
        close_con(con, cursor)

#插入及更新更新历史数据
def update_history():
    cursor = None
    con = None
    try:
        dic = get_tencent_data()[0] #0代表历史数据字典
        print(f"{time.asctime()} 开始更新历史数据")
        con,cursor = get_con()
        sql = "insert into history values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
        sql_query = "select confirm from history where ds=%s"
        for k,v in dic.items():
            # 判断最新时间的数据是否在数据表中,不在更新数据
            if not cursor.execute(sql_query,k):
                cursor.execute(sql, [k, v.get("confirm"), v.get("confirm_add"), v.get("local_confirm"),
                                     v.get("local_confirm_add"), v.get("local_no_infect"), v.get("local_no_infect_add"),
                                     v.get("heal"), v.get("heal_add"),
                                     v.get("dead"), v.get("dead_add")])
        con.commit()
        print(f"{time.asctime()} 历史数据更新完毕")
    except:
        traceback.print_exc()
    finally:
        close_con(con,cursor)


if __name__ == "__main__":
    # print(get_tencent_data())

    # 插入、更新每日details数据
    update_details()
    # 插入、更新历史数据
    update_history()

在这里插入图片描述
在这里插入图片描述

代码执行说明

先在mysql数据库中执行sql语句建表,然后修改代码中的数据库配置,然后运行代码即可!

结语

之所以做这个是因为我的项目需要数据!
正好我最近做的项目完工了,已开源。
项目地址:https://gitee.com/aniu-666/project
项目拿走不谢,还请给个star💖

  • 34
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 28
    评论
可以使用 Python 中的 BeautifulSoup 和 requests 库来爬取新浪疫情数据,并使用 MySQL 或者 MongoDB 等数据库进行存储。 以下是一个示例代码: ```python import requests from bs4 import BeautifulSoup import pymysql # 获取新浪疫情数据页面 url = 'https://news.sina.com.cn/2019-ncov/global-' res = requests.get(url) # 解析页面内容 soup = BeautifulSoup(res.text,'html.parser') # 获取全球疫情数据表格 table = soup.find('table', {'class': 'table'}) # 获取表格中的所有行 rows = table.find_all('tr') # 连接数据库 conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='covid19', charset='utf8mb4') # 创建游标 cur = conn.cursor() # 循环插入数据数据库 for row in rows[1:]: # 获取每行数据 data = row.find_all('td') # 提取数据 country = data[0].text.strip() confirmed = int(data[1].text.strip().replace(',', '')) deaths = int(data[2].text.strip().replace(',', '')) recovered = int(data[3].text.strip().replace(',', '')) # 插入数据数据库 sql = "INSERT INTO covid19 (country, confirmed, deaths, recovered) VALUES (%s, %s, %s, %s)" val = (country, confirmed, deaths, recovered) cur.execute(sql, val) conn.commit() # 关闭连接 cur.close() conn.close() ``` 在上述代码中,我们首先使用 requests 库发送 GET 请求获取新浪疫情数据页面,然后使用 BeautifulSoup 库解析页面内容,获取全球疫情数据表格,并使用 find_all() 方法获取表格中的所有行。 接着,我们使用 pymysql 库连接 MySQL 数据库,并使用游标插入数据数据库中。在插入数据时,我们首先提取每行数据的国家、确诊数、死亡数和治愈数,并使用 INSERT INTO 语句将数据插入到数据库中。 最后,我们关闭游标和数据库连接。 需要注意的是,在运行代码之前需要先创建数据库和表,代码中的数据库名为 covid19,表名为 covid19,表结构如下: ```sql CREATE TABLE covid19 ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, country VARCHAR(255) NOT NULL, confirmed INT(11) NOT NULL, deaths INT(11) NOT NULL, recovered INT(11) NOT NULL ) ``` 以上代码仅供参考,具体实现需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱音斯坦牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值