赞
踩
本文是基于大数据方向MongoDB数据库的气温可视化项目,旨在让大家认识到MongDB数据库的使用,以及作为一个数据库该如何存储数据及取出数据,如何连接前后端,将数据展示出来。 涉及到的技术包含有Python爬虫、MongoDB的Java API,Flask框架、echarts可视化,作为一个练手小项目。
编写一个爬虫程序从天气网站上爬取所需要的数据。这里爬取某市一年的天气。
爬取数据网址为:https://lishi.tianqi.com/huangshi.html,并且可以根据想要爬取的年份月份更改网址。
根据网站源代码编写爬取程序,需要注意的是,由于MongoDB的文档数据以BSON(JSON格式的一种拓展)格式存储,可以存储列表、key-value以及层次结构更加复杂的文档。我们需要将爬取到的数据添加列表中并转换成json数据文件存储,以便后续将数据存入数据库中:
- import requests # 模拟浏览器进行网络请求
- from lxml import etree # 进行数据预处理
- import json
-
-
- def getWeather(uurl):
- weather_info = [] # 新建一个列表,将爬取的每月数据放进去
- # 请求头信息:浏览器版本型号,接收数据的编码格式
- headers = {
- 'User-Agent':
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 '
- 'Safari/537.36 Edg/118.0.2088.76'
- }
- # 请求
- resp = requests.get(uurl, headers=headers)
- # 数据预处理
- resp_html = etree.HTML(resp.text)
- # xpath提取所有数据
- resp_list = resp_html.xpath("//ul[@class='thrui']/li")
- # for循环迭代遍历
- for li in resp_list:
- day_weather_info = {'data_time': li.xpath("./div[1]/text()")[0].split(' ')[0]}
- # 日期
- # 最高气温(包含摄氏度符号)
- high = li.xpath("./div[2]/text()")[0]
- day_weather_info['high'] = high[:high.find('℃')]
- # 最低气温
- low = li.xpath("./div[3]/text()")[0]
- day_weather_info['low'] = low[:low.find('℃')]
- # 天气
- day_weather_info['weather'] = li.xpath("./div[4]/text()")[0]
- weather_info.append(day_weather_info)
- return weather_info
-
-
- weathers = []
-
- # for循环生成有顺序的1-12
- for month in range(1, 13):
- # 获取某一月的天气
- # 三元表达式
- weather_time = '2023' + ('0' + str(month) if month < 10 else str(month))
- print(weather_time)
- url = f'https://lishi.tianqi.com/huangshi/{weather_time}.html'
- weather = getWeather(url)
- weathers.append(weather)
-
- # 将列表数据存储为JSON文件
- with open('month_data.json', 'w') as file:
- json.dump(weathers, file, indent=4)
- print(weathers)

将爬取出来的数据转成json文件后,存储格式如下:
环境准备(基于Hadoop集群的相关操作):
启动:myhadoop.sh start
启动:MongoDB
$/opt/module/mongodb-5.0.5/bin/mongod -f
/opt/module/mongodb-5.0.5/conf/mongo.conf
$ /opt/module/mongodb-5.0.5/bin/mongo --host 127.0.0.1 --port 27017
注意:以上启动是基于Hadoop集群上的MongoDB操作,开启虚拟机,在xshell启动。
使用爬虫获取的数据满足大数据分析的基本条件,本次实验使用的气温数据需要利用Java API插入到数据库中。
创建一个maven项目,idea项目结构如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.example</groupId>
- <artifactId>mongodbDemo</artifactId>
- <version>1.0-SNAPSHOT</version>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>7</source>
- <target>7</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <dependencies>
- <!--单元测试依赖-->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.12</version>
- </dependency>
- <!--java操作mongoDB的驱动依赖-->
- <dependency>
- <groupId>org.mongodb</groupId>
- <artifactId>mongo-java-driver</artifactId>
- <version>3.12.1</version>
- </dependency>
-
- <dependency>
- <groupId>com.googlecode.json-simple</groupId>
- <artifactId>json-simple</artifactId>
- <version>1.1.1</version>
- </dependency>
- </dependencies>
-
- </project>

其中封装了MongoDB工具类通过连接池获取对象访问服务器的方法。
- package com.sjy.util;
- import com.mongodb.MongoClient;
- import com.mongodb.MongoClientOptions;
- import com.mongodb.ServerAddress;
- /**
- * 封装MongoDB工具类通过连接池获取对象访问服务器
- */
- public class MongoDBUtil {
- private static MongoClient mongoClient = null;
- private static MongoClientOptions.Builder builder = null;
- private static MongoClientOptions options = null;
- //服务器IP
- private static String HOST = "192.168.10.102";
- //端口
- private static int PORT = 27017;
- //用户名
- private static String USER = "root";
- //密码
- private static String PASSWORD = "111111";
- //与目标数据库可以建立的最大链接数
- private static int CONNECTIONS_PERHOST = 100;
- //这个参数是跟connectionPerHost配套的,当连接超过connectionPerHost的时候,需要建立新的连接
- //连接请求会被阻塞,这个参数就代表允许阻塞请求的最大值,超过这个值之后的请求都会报错
- private static int THREADS_ALLOWED_TO_BLOCK_FOR_CONNECTION_MULTIPLIER = 100;
- //与数据库建立链接的超过时间
- private static int CONNECT_TIMEOUT = 1000 * 60 * 20;
- //一个线程成功获取到一个可用数据库之前的最大等待时间
- private static int MAX_WAILTIME = 100 * 60 * 5;
- //执行IO操作的超过时间,默认为0,代表不超时
- private static int SOCKE_TIMEOUT = 0;
-
- /**
- * 初始化连接池
- */
- static {
- try {
- builder = new MongoClientOptions.Builder();
- // builder.set
- builder.connectionsPerHost(CONNECTIONS_PERHOST);
- builder.threadsAllowedToBlockForConnectionMultiplier(THREADS_ALLOWED_TO_BLOCK_FOR_CONNECTION_MULTIPLIER);
- builder.connectTimeout(CONNECT_TIMEOUT);
- builder.maxWaitTime(MAX_WAILTIME);
- builder.socketTimeout(SOCKE_TIMEOUT);
- options = builder.build();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 通过连接池获取连接对象并操作服务器
- */
- public static MongoClient getMongoClient() {
- if (mongoClient != null) {
- return mongoClient;
- }
- try {
- mongoClient = new MongoClient(new ServerAddress(HOST, PORT), options);
- return mongoClient;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- /**
- * 释放资源
- */
- public static void close(MongoClient mongoClient) {
- if (mongoClient != null) {
- mongoClient.close();
- }
- }
- }

首先创建一个MongoClient实例来连接到本地运行在默认端口上的MongoDB服务器。接着,我们获取目标数据库和集合的引用。
接下来,创建一个新的Document对象,并将JSONObject中的所有键值对添加到这个Document对象中。最后,将这个Document对象插入到MongoDB集合中。这里的json文件就是上述爬虫程序爬取到的数据文件。
- package com.sjy.mongodb;
-
- import com.mongodb.MongoClient;
- import com.mongodb.client.FindIterable;
- import com.mongodb.client.MongoCollection;
- import com.mongodb.client.MongoDatabase;
- import com.sjy.util.MongoDBUtil;
- import org.bson.Document;
- import org.json.simple.JSONArray;
- import org.json.simple.JSONObject;
- import org.json.simple.parser.JSONParser;
- import org.json.simple.parser.ParseException;
- import java.io.FileReader;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.UUID;
-
- public class WeatherTest {
- public static void main(String[] args) {
- // 连接到MongoDB服务器
- MongoClient mongoClient = MongoDBUtil.getMongoClient();
- // 获取数据库和集合实例
- MongoDatabase database = mongoClient.getDatabase("my_database");
- MongoCollection<Document> collection = database.getCollection("weather");
- // 从JSON文件中读取数据
- List<Document> documents = new ArrayList<>();
- JSONParser parser = new JSONParser();
- try (FileReader reader = new FileReader("d:/data.json")) {
- Object obj = parser.parse(reader);
-
- JSONArray jsonArray = (JSONArray) obj;
- for (Object o : jsonArray) {
- JSONObject jsonObject = (JSONObject) o;
- String id = UUID.randomUUID().toString();
- Document document = new Document("_id", id)
- .append("data_time", jsonObject.get("data_time"))
- .append("high", jsonObject.get("high"))
- .append("low", jsonObject.get("low"))
- .append("weather", jsonObject.get("weather"));
- documents.add(document);
- }
-
- } catch (IOException | ParseException e) {
- System.err.println("Error reading data from file: " + e.getMessage());
- }
- // 执行批量插入
- collection.insertMany(documents);
- FindIterable<Document> weatherDo = collection.find();
- for (Document document : weatherDo) {
- System.out.println(document.toJson());
- }
- // 关闭MongoClient连接
- mongoClient.close();
- }
- }

最后测试数据是否插入成功
为了更好地理解和解释分析结果,我们使用Echarts创建了一系列图表,包括柱状图、饼图。这些可视化工具使我们能够直观地看到数据的模式和趋势。
本次项目可视化我使用了Python的flask框架作为后端。Flask是一个微框架,它比其他如Django等大型框架更简洁、轻巧。这意味着我可以快速搭建一个小型应用,并且在不引入过多额外依赖的情况下专注于核心功能——数据可视化。Flask默认集成了Jinja2模板引擎,它可以方便地将数据插入到HTML页面中,这对于动态生成包含可视化的网页非常有用。
引入项目所需库,连接MongoDB数据库,执行find()方法,获取所需要的数据,并将需要的数据添加到列表中发送给前端。本次实验需要的数据是日期、该日最高温度和最低温度。
- from flask import Flask, render_template, request
- # render_template作用是把html网页渲染完然后扔给服务器
- import pymongo
- import json
- # 创建一个app
- app = Flask(__name__)
- # 连接到MongoDB数据库
- client = pymongo.MongoClient("mongodb://192.168.10.102:27017/")
- # 选择数据库
- db = client["my_database"]
- # 选择集合
- collection = db["weather"]
- # 创建游标对象
- cursor = collection.find()
- data_time = []
- high = []
- low = []
- weather = {}
-
- for document in cursor:
- print(document)
- data_time.append(document.get('data_time')[5:])
- high.append(document.get('high'))
- low.append(document.get('low'))
-
- data = {
- 'data_time': data_time,
- 'high': high,
- 'low': low
- }
-
- @app.route("/")
- def show():
- return render_template("show.html", data=data)
-
-
- # 运行这个app
- if __name__ == '__main__':
- app.run()

本次项目可视化我使用ECharts 库,在前端代码中引入ECharts标签<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.common.min.js"></script> ECharts 是一个由百度商业前端数据可视化团队开发的开源数据可视化库。它基于 JavaScript,能够创建丰富的图表和图形,包括折线图、柱状图、饼图、地图等,用于展示和分析数据。并且ECharts 有一个清晰的 API 和详细的文档,开发者可以快速上手并创建出复杂的图表。
html代码,使用了echarts示例中的折线图,可以更清晰的展现某市上一个月的气温变化。
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <!--引入echarts-->
- <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.common.min.js"></script>
- </head>
- <body>
- <div id="weather" style="width: 1000px; height: 700px;"></div>
-
-
- <script>
- // 获取从后端传递的数据
- var weather = echarts.init(document.getElementById("weather"))
-
- var option = {
- title: {
- text: '黄石市2023年11月气温变化'
- },
- tooltip: {
- trigger: 'axis'
- },
- legend: {},
- toolbox: {
- show: true,
- feature: {
- dataZoom: {
- yAxisIndex: 'none'
- },
- dataView: { readOnly: false },
- magicType: { type: ['line', 'bar'] },
- restore: {},
- saveAsImage: {}
- }
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: {{data.data_time|tojson}}
- },
- yAxis: {
- type: 'value',
- axisLabel: {
- formatter: '{value} °C'
- }
- },
- series: [
- {
- name: 'Highest',
- type: 'line',
- data: {{data.high|tojson}},
- markPoint: {
- data: [
- { type: 'max', name: 'Max' },
- { type: 'min', name: 'Min' }
- ]
- },
- markLine: {
- data: [{ type: 'average', name: 'Avg' }]
- }
- },
- {
- name: 'Lowest',
- type: 'line',
- data: {{data.low|tojson}},
- // markPoint: {
- // data: [{ name: '周最低', value: -2, xAxis: 1, yAxis: -1.5 }]
- // },
- markLine: {
- data: [
- { type: 'average', name: 'Avg' },
- [
- {
- symbol: 'none',
- x: '90%',
- yAxis: 'max'
- },
- {
- symbol: 'circle',
- label: {
- position: 'start',
- formatter: 'Max'
- },
- type: 'max',
- name: '最高点'
- }
- ]
- ]
- }
- }
- ]
- };
- //把配置单给echarts
- weather.setOption(option)
-
- </script>
-
- </body>
- </html>

本实验的主要目标是使用MongoDB数据库存储黄石市上一个月的气温数据,并通过可视化的手段展示结果。我们首先使用Python爬虫从天气网站上抓取了一年内的所有气温数据。然后,将数据转存为json格式,确保后续使用Java API存储到MongoDB数据库中数据文件的解析性。最后使用flask框架连接MongoDB数据库,查询出存储的所有气温数据,再过滤出我们需要的数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。