[add] 初始資料
This commit is contained in:
parent
8f9840cb6b
commit
8f0b08f3a7
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
package-lock.json
|
||||||
|
*.pem
|
||||||
|
.foreverignore
|
||||||
|
.vscode
|
283
CPBLClass.js
Normal file
283
CPBLClass.js
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
const dateFormat = require('dateformat');
|
||||||
|
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
const { decode } = require('querystring');
|
||||||
|
const tools = require('../tools/tools');
|
||||||
|
|
||||||
|
/** CPBL */
|
||||||
|
class CPBLClass {
|
||||||
|
// constructor(bot, JianMiaubot, Tools_MYSQLDB) {
|
||||||
|
// this.bot = bot;
|
||||||
|
// this.JianMiaubot = JianMiaubot;
|
||||||
|
// this.Tools_MYSQLDB = Tools_MYSQLDB;
|
||||||
|
// }
|
||||||
|
|
||||||
|
async GetCPBL(data) {
|
||||||
|
let url = data["URL"];
|
||||||
|
let Response = await this.GetData(url);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 傳入 resolve 與 reject,表示資料成功與失敗
|
||||||
|
resolve(this.ParseCPBL(Response));
|
||||||
|
// reject()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async GetCPBLList(data) {
|
||||||
|
// let url = "http://www.cpbl.com.tw/schedule/index";
|
||||||
|
let datetime = dateFormat(new Date(), "yyyymmdd");
|
||||||
|
let year = datetime.substr(0, 4);
|
||||||
|
let month = datetime.substr(4, 2);
|
||||||
|
let day = datetime.substr(6, 2);
|
||||||
|
let date = data["Date"];
|
||||||
|
let url = `http://www.cpbl.com.tw/schedule/index/${year}-${month}-${day}.html?&date=${year}-${month}-${day}&gameno=01&sfieldsub=&sgameno=01`;
|
||||||
|
let Response = await this.GetData(url);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 傳入 resolve 與 reject,表示資料成功與失敗
|
||||||
|
resolve(this.ParseCPBLList(Response, date));
|
||||||
|
// reject()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseCPBL(htmlString) {
|
||||||
|
let index_obj = {
|
||||||
|
"1上": 0,
|
||||||
|
"1下": 1,
|
||||||
|
"2上": 2,
|
||||||
|
"2下": 3,
|
||||||
|
"3上": 4,
|
||||||
|
"3下": 5,
|
||||||
|
"4上": 6,
|
||||||
|
"4下": 7,
|
||||||
|
"5上": 8,
|
||||||
|
"5下": 9,
|
||||||
|
"6上": 10,
|
||||||
|
"6下": 11,
|
||||||
|
"7上": 12,
|
||||||
|
"7下": 13,
|
||||||
|
"8上": 14,
|
||||||
|
"8下": 15,
|
||||||
|
"9上": 16,
|
||||||
|
"9下": 17,
|
||||||
|
};
|
||||||
|
// htmlString = htmlString.replace('/\\r\\n/g', '').replace('/\\t/g', '').replace('/\\\"/g', '"');
|
||||||
|
// let htmlString1 = htmlString.replace(/\r\n|\n|\t/g, "");
|
||||||
|
// htmlString1 = htmlString1.replace(/\\/g, '');
|
||||||
|
// let htmlString1 = '';
|
||||||
|
// const html = document.createElement('html');
|
||||||
|
// html.innerHTML = htmlString;
|
||||||
|
// const title = document.getElementsByTagName('title')[0].innerText // 取得title:我的標題
|
||||||
|
// 把 body 放進 cheerio 準備分析
|
||||||
|
const $ = cheerio.load(htmlString); // 載入 body
|
||||||
|
const result = []; // 建立一個儲存結果的容器
|
||||||
|
// const table_tr = $("tbody tr"); // 爬最外層的 Table(class=BoxTable) 中的 tr
|
||||||
|
const table_tr = $(".gap_b20 table tbody tr"); // 爬最外層的 Table(class=BoxTable) 中的 tr
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
let _result = JSON.parse("[]");
|
||||||
|
for (let i = 0; i < table_tr.length; i++) { // 走訪 tr
|
||||||
|
const table_td = table_tr.eq(i).find('td'); // 擷取每個欄位(td)
|
||||||
|
const table_th = table_tr.eq(i).find('th'); // 擷取每個欄位(td)
|
||||||
|
let title = table_td.eq(1).text(); // time (台灣時間)
|
||||||
|
if (!title) {
|
||||||
|
title = table_th.eq(0).text();
|
||||||
|
}
|
||||||
|
// const latitude = table_td.eq(2).text(); // latitude (緯度)
|
||||||
|
// const longitude = table_td.eq(3).text(); // longitude (經度)
|
||||||
|
// const amgnitude = table_td.eq(4).text(); // magnitude (規模)
|
||||||
|
// const depth = table_td.eq(5).text(); // depth (深度)
|
||||||
|
// const location = table_td.eq(6).text(); // location (位置)
|
||||||
|
// const url = table_td.eq(7).text(); // url (網址)
|
||||||
|
// 建立物件並(push)存入結果
|
||||||
|
// result.push(Object.assign({ time, latitude, longitude, amgnitude, depth, location, url }));
|
||||||
|
if (title) {
|
||||||
|
if (table_th.eq(0).text()) {
|
||||||
|
index = index_obj[title];
|
||||||
|
}
|
||||||
|
_result[index] = _result[index] ? _result[index] : [];
|
||||||
|
_result[index].push(Object.assign({ title }));
|
||||||
|
result.push(Object.assign({ title }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// request({
|
||||||
|
// url: "http://www.cpbl.com.tw/games/play_by_play.html?&game_type=01&game_id=62&game_date=2021-04-18&pbyear=2021", // 中央氣象局網頁
|
||||||
|
// method: "GET"
|
||||||
|
// }, function (error, response, body) {
|
||||||
|
// if (error || !body) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// const $ = cheerio.load(body); // 載入 body
|
||||||
|
// const result = []; // 建立一個儲存結果的容器
|
||||||
|
// // const table_tr = $("tbody tr"); // 爬最外層的 Table(class=BoxTable) 中的 tr
|
||||||
|
// const table_tr = $(".gap_b20 table tbody tr"); // 爬最外層的 Table(class=BoxTable) 中的 tr
|
||||||
|
|
||||||
|
// for (let i = 0; i < table_tr.length; i++) { // 走訪 tr
|
||||||
|
// const table_td = table_tr.eq(i).find('td'); // 擷取每個欄位(td)
|
||||||
|
// const table_th = table_tr.eq(i).find('th'); // 擷取每個欄位(td)
|
||||||
|
// let title = table_td.eq(1).text(); // time (台灣時間)
|
||||||
|
// if (!title) {
|
||||||
|
// title = table_th.eq(0).text();
|
||||||
|
// }
|
||||||
|
// // const latitude = table_td.eq(2).text(); // latitude (緯度)
|
||||||
|
// // const longitude = table_td.eq(3).text(); // longitude (經度)
|
||||||
|
// // const amgnitude = table_td.eq(4).text(); // magnitude (規模)
|
||||||
|
// // const depth = table_td.eq(5).text(); // depth (深度)
|
||||||
|
// // const location = table_td.eq(6).text(); // location (位置)
|
||||||
|
// // const url = table_td.eq(7).text(); // url (網址)
|
||||||
|
// // 建立物件並(push)存入結果
|
||||||
|
// // result.push(Object.assign({ time, latitude, longitude, amgnitude, depth, location, url }));
|
||||||
|
// if (title) {
|
||||||
|
// result.push(Object.assign({ title }));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // 在終端機(console)列出結果
|
||||||
|
// console.log("result");
|
||||||
|
// // 寫入 result.json 檔案
|
||||||
|
// // fs.writeFileSync("result.json", JSON.stringify(result));
|
||||||
|
// });
|
||||||
|
// $('.gap_b20 .std_tb mix_line gap_t10 overwrite_size_15 tbody tr').each(function (i, elem) {
|
||||||
|
// weathers.push($(this).text().split('\n'));
|
||||||
|
// });
|
||||||
|
return JSON.stringify(_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseCPBLList(htmlString, date) {
|
||||||
|
let month = +dateFormat(new Date(), "mm") - 1;
|
||||||
|
const $ = cheerio.load(htmlString); // 載入 body
|
||||||
|
const result = {}; // 建立一個儲存結果的容器
|
||||||
|
let map = new Map();
|
||||||
|
let set = 0;
|
||||||
|
let get = 0;
|
||||||
|
// const table_tr = $("tbody tr"); // 爬最外層的 Table(class=BoxTable) 中的 tr
|
||||||
|
// const table_tr = $(".gap_b20 table tbody tr"); // 爬最外層的 Table(class=BoxTable) 中的 tr
|
||||||
|
const table_tr = $(".schedule.gap_t20.gap_b20 tbody").children().first().siblings("tr");
|
||||||
|
table_tr.splice(0, 0, $(".schedule.gap_t20.gap_b20 tbody").children().first()[0]);
|
||||||
|
// const aaa = table_tr.children().first().nextAll();
|
||||||
|
// const aaa = table_tr.find('.one_block');
|
||||||
|
// const bbb = aaa.eq(0).attr('onclick');
|
||||||
|
let index = 0;
|
||||||
|
// let _result = JSON.parse("[]");
|
||||||
|
// for (let i = 0; i < table_tr.length; i++) { // 走訪 tr
|
||||||
|
// const table_td = table_tr.eq(i).find('td'); // 擷取每個欄位(td)
|
||||||
|
// const table_th = table_tr.eq(i).find('th'); // 擷取每個欄位(td)
|
||||||
|
// let address = table_td.eq(1).text(); // time (台灣時間)
|
||||||
|
// let img1 = table_td.eq(0).find('img').attr('src'); // time (台灣時間)
|
||||||
|
// let img2 = table_td.eq(2).find('img').eq(0).attr('src'); // time (台灣時間)
|
||||||
|
// if (!address) {
|
||||||
|
// address = table_th.eq(0).text();
|
||||||
|
// }
|
||||||
|
// if (address) {
|
||||||
|
// // if (table_th.eq(0).text()) {
|
||||||
|
// // index = index_obj[title];
|
||||||
|
// // }
|
||||||
|
// // _result[index] = _result[index] ? _result[index] : [];
|
||||||
|
// // _result[index].push(Object.assign({ title }));
|
||||||
|
// result.push(Object.assign({ title: address }));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
for (let i = 0; i < table_tr.length; i++) {
|
||||||
|
let table = [];
|
||||||
|
let td = table_tr.eq(i).children().first().siblings("td");
|
||||||
|
let th = table_tr.eq(i).children().first().siblings("th");
|
||||||
|
if (table_tr[i].attribs.class === "day") {
|
||||||
|
th.splice(0, 0, table_tr.eq(i).children().first()[0]);
|
||||||
|
table = th;
|
||||||
|
} else if (th.length > 0) {
|
||||||
|
th.splice(0, 0, table_tr.eq(i).children().first()[0]);
|
||||||
|
for (let j = 0; j < th.length; j++) {
|
||||||
|
let index = th.eq(j).text();
|
||||||
|
if (+index === 1) {
|
||||||
|
month++;
|
||||||
|
}
|
||||||
|
index = "2021" + tools.padLeft(month, 2) + index;
|
||||||
|
result[index] = [];
|
||||||
|
map.set(set, index);
|
||||||
|
set++;
|
||||||
|
}
|
||||||
|
table = th;
|
||||||
|
} else if (td.length > 0) {
|
||||||
|
td.splice(0, 0, table_tr.eq(i).children().first()[0]);
|
||||||
|
for (let j = 0; j < td.length; j++) {
|
||||||
|
// let div = td.eq(j).children().first().siblings("div");
|
||||||
|
let div = td.eq(j).find("div");
|
||||||
|
if (div.length > 0) {
|
||||||
|
for (let k = 0; k < div.length; k++) {
|
||||||
|
let table1 = div.eq(k).children().first().siblings("table");
|
||||||
|
table1.splice(0, 0, div.eq(k).children().first()[0]);
|
||||||
|
for (let l = 0; l < table1.length; l++) {
|
||||||
|
if (table1[l].attribs.class === "schedule_team") {
|
||||||
|
let date = map.get(get);
|
||||||
|
let schedule_team = table1.eq(0).find('td');
|
||||||
|
let img1 = schedule_team.eq(0).find('img').attr('src');
|
||||||
|
let address = schedule_team.eq(1).text();
|
||||||
|
let img2 = schedule_team.eq(2).find('img').attr('src');
|
||||||
|
let schedule_info3 = table1.eq(3).find('td');
|
||||||
|
let time = schedule_info3.eq(1).text();
|
||||||
|
let href = {};
|
||||||
|
if (!time) {
|
||||||
|
href = decode(div[k].attribs.onclick.split("?")[1]);
|
||||||
|
} else {
|
||||||
|
let schedule_info1 = table1.eq(1).find('th');
|
||||||
|
let game_type = "01";
|
||||||
|
let game_id = schedule_info1.eq(1).text();
|
||||||
|
let game_date = `${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}`;
|
||||||
|
let pbyear = date.substr(0, 4);
|
||||||
|
href = {
|
||||||
|
time: schedule_info3.eq(1).text(),
|
||||||
|
game_type: game_type,
|
||||||
|
game_id: game_id,
|
||||||
|
game_date: game_date,
|
||||||
|
pbyear: pbyear
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let Data = {
|
||||||
|
img1: img1,
|
||||||
|
address: address,
|
||||||
|
img2: img2,
|
||||||
|
href: href
|
||||||
|
};
|
||||||
|
result[date].push(Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get++;
|
||||||
|
}
|
||||||
|
table = td;
|
||||||
|
}
|
||||||
|
// for (let j = 0; j < table.length; j++) {
|
||||||
|
// let address = table.eq(j).text();
|
||||||
|
// if (address) {
|
||||||
|
// result.push(Object.assign({ title: address }));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return JSON.stringify(result[date]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得表
|
||||||
|
* @param Url Url
|
||||||
|
* @param arrange 是否需要整理
|
||||||
|
*/
|
||||||
|
GetData(Url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
if (xhr.readyState === 4) {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 400) {
|
||||||
|
var response = xhr.responseText;
|
||||||
|
resolve(response);
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.open("GET", Url, true);
|
||||||
|
xhr.send();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CPBLClass
|
96
app.js
Normal file
96
app.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// 背景執行 forever start -w -a -l api.log app.js
|
||||||
|
// 監聽檔案變化 nodemon app.js
|
||||||
|
// npm start
|
||||||
|
// npm run dev
|
||||||
|
// Debug nodemon --inspect=192.168.168.15:9229 app.js
|
||||||
|
|
||||||
|
const dateFormat = require('dateformat');
|
||||||
|
require('dotenv').config()
|
||||||
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
|
const fs = require('fs');
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
//讀取憑證及金鑰
|
||||||
|
const prikey = fs.readFileSync('privkey.pem', 'utf8');
|
||||||
|
const cert = fs.readFileSync('cert.pem', 'utf8');
|
||||||
|
const cafile = fs.readFileSync('chain.pem', 'utf-8');
|
||||||
|
|
||||||
|
//建立憑證及金鑰
|
||||||
|
const credentials = {
|
||||||
|
key: prikey,
|
||||||
|
cert: cert,
|
||||||
|
ca: cafile
|
||||||
|
};
|
||||||
|
|
||||||
|
const CPBLClass = require('./CPBLClass');
|
||||||
|
const { decode } = require('querystring');
|
||||||
|
const CPBL = new CPBLClass();
|
||||||
|
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
const server = https.createServer(credentials, async function (req, res) {
|
||||||
|
// const server = http.createServer(async function (req, res) {
|
||||||
|
// console.log(`rawBody: ${req.rawBody}`);
|
||||||
|
// res.writeHead(200);
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
// console.log(`body: ${JSON.stringify(req.body)}`);
|
||||||
|
let Request = req.url.replace("/", "");
|
||||||
|
let Response = "";
|
||||||
|
let data = '';
|
||||||
|
req.on('data', chunk => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
req.on('end', async () => {
|
||||||
|
switch (req.headers["content-type"]) {
|
||||||
|
case "application/x-www-form-urlencoded": {
|
||||||
|
data = decode(data);
|
||||||
|
// data = []
|
||||||
|
// let strs = str.split("&");
|
||||||
|
// for (let i = 0; i < strs.length; i++) {
|
||||||
|
// data[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "application/json": {
|
||||||
|
data = JSON.parse(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (Request) {
|
||||||
|
case "CPBL":
|
||||||
|
Response = await CPBL.GetCPBL(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "CPBLList":
|
||||||
|
Response = await CPBL.GetCPBLList(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res.writeHead(200);
|
||||||
|
res.write(Response);
|
||||||
|
return res.end();
|
||||||
|
});
|
||||||
|
// } else if (req.method === 'GET' && req.url === path) {
|
||||||
|
// let Response = await CPBL.GetCPBL();
|
||||||
|
// res.writeHead(200);
|
||||||
|
// res.write(Response);
|
||||||
|
// return res.end();
|
||||||
|
} else {
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||||
|
return res.end('Not found');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.listen(port, function () {
|
||||||
|
let datetime = dateFormat(new Date(), "yyyy-mm-dd HH:MM:ss");
|
||||||
|
console.log(`${datetime} listening on ${port}`);
|
||||||
|
console.log(`${datetime} [api已準備就緒]`);
|
||||||
|
});
|
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "cpbl",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "forever start -a -l api.log app.js",
|
||||||
|
"dev": "nodemon --inspect=127.0.0.1:9229 app.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"cheerio": "^1.0.0-rc.6",
|
||||||
|
"dateformat": "^4.5.1",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"http": "0.0.1-security",
|
||||||
|
"https": "^1.0.0",
|
||||||
|
"node-html-parser": "^3.1.5",
|
||||||
|
"nodemon": "^2.0.7",
|
||||||
|
"request": "^2.88.2",
|
||||||
|
"xmlhttprequest": "^1.8.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user