diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..adae22e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+data/
+
+package-lock.json
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1df9edf
--- /dev/null
+++ b/package.json
@@ -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"
+ }
+}
diff --git a/src/index.html b/src/index.html
new file mode 100644
index 0000000..ce979fb
--- /dev/null
+++ b/src/index.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+ | 地区 |
+ 92# |
+ 95# |
+ 0# |
+
+
+
+
+
+
+
+
+ 数据来源:小熊油耗
+ 更新时间:
+
+ 免责声明:本数据仅供参考,具体油价请以当地加油站实际价格为准。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..ba8bf9a
--- /dev/null
+++ b/src/index.js
@@ -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}`
+}