feat: 完成基本功能

This commit is contained in:
2025-05-12 21:49:32 +08:00
parent 5575ce6ada
commit 0d7e254cf4
4 changed files with 234 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules/
data/
package-lock.json

21
package.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "oil",
"version": "1.0.0",
"description": "查询当前油价",
"keywords": [
"oil"
],
"license": "GPL-3.0-or-later",
"author": "hbk01",
"type": "module",
"main": "index.js",
"scripts": {
"test": "nodemon ./src/index.js"
},
"dependencies": {
"axios": "^1.9.0",
"cheerio": "^1.0.0",
"express": "^5.1.0",
"nodemon": "^3.1.10"
}
}

82
src/index.html Normal file
View File

@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>油价</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(() => {
$.getJSON('/query', (data) => {
const tableBody = $('#table-body');
data.forEach(item => {
if (item.name == "更新时间") {
$('#update-time').text(item.time.replace("T", " "))
} else {
const row = `<tr>
<td>${item.name}</td>
<td>${item["92#"]}</td>
<td>${item["95#"]}</td>
<td>${item["0#"]}</td>
</tr>`
tableBody.append(row)
}
})
}).fail(() => {
alert('数据加载失败,请稍后再试。')
})
})
</script>
<style>
table {
table-layout: fixed;
width: 100%;
border-collapse: collapse;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
thead tr th {
background-color: #f2f2f2;
color: black;
position: sticky;
top: 0;
}
th,
td {
padding: 10px;
text-align: center;
border-bottom: 1px solid gray;
}
</style>
</head>
<body>
<div class="content">
<table>
<thead>
<tr>
<th>地区</th>
<th>92#</th>
<th>95#</th>
<th> 0#</th>
</tr>
</thead>
<tbody id="table-body">
</tbody>
</table>
<div style="margin-top: 50px;">
<p>
数据来源:小熊油耗<br>
更新时间:<span id="update-time"></span>
<p>
<span style="color: red;">免责声明:本数据仅供参考,具体油价请以当地加油站实际价格为准。</span>
</p>
</p>
</div>
</body>
</html>

127
src/index.js Normal file
View File

@@ -0,0 +1,127 @@
import axios from 'axios'
import * as cheerio from 'cheerio'
import express from 'express'
import path from 'path'
import fs from 'fs'
const app = express()
const __dirname = path.resolve()
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'src', 'index.html'))
})
app.get('/query', async (req, res) => {
let { name, force } = req.query
if (force == undefined) {
force = false
}
const data = getOilPriceJson(force)
if (name) {
const filteredData = data.filter(item => item.name.includes(name))
res.json(filteredData)
} else {
res.json(data)
}
})
app.listen(1933, () => {
console.log('Server is running on port 1933')
});
// 获取油价数据,若本地数据存在则读取本地数据,否则请求网络数据,并保存到本地以供后续使用。
// force 参数用于强制刷新本地数据
const getOilPriceJson = (force) => {
const filename = new Date().format().split("T")[0].replaceAll("-", "").concat(".json")
const filepath = path.join(__dirname, "data", filename)
if (fs.existsSync(filepath) && !force) {
const data = fs.readFileSync(filepath, "utf-8")
return JSON.parse(data)
} else {
// 如果目录不存在,则创建目录
if (!fs.existsSync(path.join(__dirname, "data"))) {
fs.mkdirSync(path.join(__dirname, "data"), { recursive: true })
}
// 如果文件存在,则需要删除文件
if (fs.existsSync(filepath)) {
fs.rmSync(filepath)
}
getOilPrice((data) => {
data.push({
name: "更新时间",
time: new Date().format()
})
fs.writeFileSync(filepath, JSON.stringify(data), "utf-8")
})
}
}
const getOilPrice = async (callback) => {
const url = "https://www.xiaoxiongyouhao.com/fprice/"
let data = []
const response = await axios.get(url)
const $ = cheerio.load(response.data)
// 解析 html 页面
$("table").each((i, elem) => {
const table = $(elem)
const rows = table.find("tr")
rows.each((j, row) => {
const cells = $(row).find("td")
let rowData = {}
cells.each((k, cell) => {
switch (k) {
case 0:
rowData["name"] = rename($(cell).text())
break
case 1:
rowData["92#"] = $(cell).text()
break
case 2:
rowData["95#"] = $(cell).text()
break
case 3:
rowData["0#"] = $(cell).text()
break
default:
rowData["other"] = $(cell).text()
break
}
})
// 过滤掉空行
if (Object.keys(rowData).length > 0) {
data.push(rowData);
}
})
})
callback(data)
}
// 统一地区名称
const rename = (name) => {
name = name.replace("省", "")
name = name.replace("市", "")
name = name.replace("内蒙古自治区", "内蒙古")
name = name.replace("广西壮族自治区", "广西")
name = name.replace("西藏自治区", "西藏")
name = name.replace("宁夏回族自治区", "宁夏")
name = name.replace("新疆维吾尔自治区", "新疆")
name = name.replace("香港特别行政区", "香港")
name = name.replace("澳门特别行政区", "澳门")
return name
}
// 为 Date 创建日期格式化方法
Date.prototype.format = function () {
let fillZero = (num) => {
return num < 10 ? "0" + num : num
}
let year = fillZero(this.getFullYear())
let month = fillZero(this.getMonth() + 1)
let day = fillZero(this.getDate())
let hour = fillZero(this.getHours())
let minute = fillZero(this.getMinutes())
let second = fillZero(this.getSeconds())
return `${year}-${month}-${day}T${hour}:${minute}:${second}`
}