当前位置: 首页 > news >正文

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

📋 个人简介

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

目录

    • 📋 个人简介
  • 前言
    • 需求分析
    • 项目技术
    • 数据库设计
      • ER图
      • 建表sql
      • pymysql连接数据库
    • 爬虫设计
    • 代码与展示
    • 代码执行说明
  • 结语

前言

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

需求分析

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

目标网站如下: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💖

相关文章:

  • 场景应用:网络的子网掩码为255.255.240.0,它能够处理的主机数是多少?
  • Qt5开发从入门到精通——第七篇六节( 图形视图—— 图元的旋转、缩放、切变、和位移)
  • 内网穿透工具natapp的注册、下载、安装与使用(详细教程)
  • CDH openssl 安装报错 TXT_DB error number 2
  • 【Linux线程同步专题】一、什么是线程同步、互斥量与死锁
  • 内网渗透-Linux权限维持
  • Git 便捷操作
  • 美国项目管理协会和埃森哲最新报告:越来越多的公司设立首席转型官一职
  • y145.第八章 Servless和Knative从入门到精通 -- 消息系统基础和Eventing及实践(九)
  • CDQ整体二分-三维偏序(陌上花开)
  • Vue3+elementplus搭建通用管理系统实例十三:添加树形选择器及多选功能
  • GBASE 8s 高可用配置参数
  • 大白话paxos raft
  • 微信小程序开发入门与实战(插槽及组件页面的生命周期)
  • QT 语言的学习 day09 进程 和 线程
  • Docker容器管理
  • Git 使用集
  • JAVA多线程机制解析-volatilesynchronized
  • jdbc就是这么简单
  • Markdown 语法简单说明
  • MaxCompute访问TableStore(OTS) 数据
  • vue的全局变量和全局拦截请求器
  • Vue小说阅读器(仿追书神器)
  • windows下使用nginx调试简介
  • 闭包,sync使用细节
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 给初学者:JavaScript 中数组操作注意点
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 前嗅ForeSpider中数据浏览界面介绍
  • 使用 @font-face
  • 使用Swoole加速Laravel(正式环境中)
  • 突破自己的技术思维
  • 王永庆:技术创新改变教育未来
  • 用mpvue开发微信小程序
  • postgresql行列转换函数
  • 阿里云服务器购买完整流程
  • 阿里云重庆大学大数据训练营落地分享
  • #ubuntu# #git# repository git config --global --add safe.directory
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (4)Elastix图像配准:3D图像
  • (HAL库版)freeRTOS移植STMF103
  • (poj1.2.1)1970(筛选法模拟)
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (生成器)yield与(迭代器)generator
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (十六)Flask之蓝图
  • .NET CLR Hosting 简介
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .Net Winform开发笔记(一)
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .Net 应用中使用dot trace进行性能诊断
  • @zabbix数据库历史与趋势数据占用优化(mysql存储查询)
  • [2010-8-30]
  • [BZOJ 2142]礼物(扩展Lucas定理)