1.node服务搭建 1)执行npm init,初始化node服务,项目目录结构为
bin文件夹用于存放打包启动相关配置
lib文件夹用于存放打包好的文件
src/app用于存放应用实例
src/config用于存放基础配置
src/gitConfig用于存放git相关配置
src/router用于存放路由相关配置(接口定义)
src/router_handler用于存放接口处理函数(接口实现)
main为入口文件
所需依赖:
cheerio:解析器/*chalk 不能使用 4.1 以上版本否则提示必须使用 es6 语法,不支持 commonjs*/
cors:防跨域
esbuild:打包器
express:项目框架
fs-extra:文件读取器
superagent:npde爬虫
superagent-proxy:爬虫代理
项目实现:
//main.js引入配置的端口,引入app应用实例
const { APP_PORT } = require('./config/config.default.js');
const { app } = require('./app/index.js');
// 之后的其他配置都写在这里
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(APP_PORT, function () {
console.log(`server is running http://localhost:${APP_PORT}`);
});
//app/index.js创建应用实例,引入定义的接口router
const express = require('express');
const cors = require('cors');
const { router } = require('../router/api.js');
// 创建 express 的服务器实例
const app = express();
app.use(cors());
app.use(express.json());
app.use(router);
exports.app = app;
//router/api.js下定义接口getApi,引入接口实现函数apiHandler
const express = require('express');
const router = express.Router();
// 导入用户路由处理函数模块
const { apiHandler } = require('../router_handler/apiHandler.js');
// 处理登录请求的映射关系
router.post('/getApi', apiHandler);
exports.router = router;
//接口实现
//引入superagent用于爬取资源
//引入cheerio用于解析资源
//引入proxySuperagent用于配置代理(如果配置代理,在打包时必须必须手动写入 bridge.js 及 setup-sandbox.js 否则使用 esbuid 打包时不会引入,导致开发模式正常,打包后编译失败)
//抛出处理函数apiHandler
//接口内部最终返回处理好的信息
const superagent = require('superagent');
const cheerio = require('cheerio');
const proxySuperagent = require('superagent-proxy');
proxySuperagent(superagent);
// const weiboURL = "http://wiki.ziroom.com/dologin.action"; // 域名
// const hotSearchURL = weiboURL + "";
let cookie = null;
// 配置代理 /
let proxyConfig = {
URL: 'http://127.0.0.1:80',
};
// 登录请求的处理函数
exports.apiHandler = async (req, res) => {
console.log(req.body, 'req');
const { url, cookie, type, gateway = null } = req.body;
let apiJson = await getApiJsonFn(url, cookie, type, gateway);
res.send(apiJson);
};
const getApiJsonFn = (url, cookie, type, gateway) => {
// 数据处理方法
return new Promise((resolve, reject) => {
superagent
.get(url)
.set('Content-Type', 'text/html;charset=UTF-8')
.set('Cookie', cookie)
.set('host', '127.0.0.1')
.proxy(proxyConfig.URL)
.end((err, res) => {
// console.log(res, '=============================================================');
if (err) console.error('e请求失败', err);
const content = res.text;
let $ = cheerio.load(content);
const _json = analysisFn($, type, gateway);
resolve(_json);
});
});
};
const analysisFn = ($, type, gateway) => {
//解析函数,书写自己的解析器内容
//const content = $('#main');
//返回解析完成的数据
return result;
};
打包及启动配置
//配置package.json下启动脚本
"scripts": {
"start": "node src/main.js",
"build": "node bin/build.js",
"serve": "node lib/index.js"
},
const esbuild = require('esbuild');
const fs = require('fs-extra');
const path = require('path');
const join = (...paths) => path.join(__dirname, ...paths);
// const npm = exec('npm');
const outfile = 'lib/index.js';
(async function () {
const builded = await esbuild.build({
outfile,
platform: 'node',
entryPoints: ['src/main.js'],
logLevel: 'silent',
format: 'cjs',
bundle: true,
// minify: true,
define: {
'process.env.NODE_ENV': '"production"',
},
});
/*!!!如果配置了代理,必须手动写入这两个文件,这两个文件为依赖包中的同名文件*/
fs.copyFileSync(join('./bridge.js'), join('../lib', 'bridge.js'));
fs.copyFileSync(join('./setup-sandbox.js'), join('../lib', 'setup-sandbox.js'));
var lemonadeChange = function(bills) {
let map=new Map()
for(let i in bills){
switch(bills[i]){
case 5:
mapAdd(map,5)
break
case 10:
if(map.has(5) && map.get(5)>=0){
mapAdd(map,10)
map.set(5,map.get(5)-1)
}else{
return false
}
break
case 20:
if(map.has(10)&&map.get(10)>=0){
if(map.has(5)&&map.get(5)>=0){
map.set(10,map.get(10)-1)
map.set(5,map.get(5)-1)
}else{
return false
}
}else{
if(map.has(5)&&map.get(5)>=2){
map.set(5,map.get(5)-3)
}else{
return false
}
}
break
}
}
return true
};
const mapAdd=(map,i)=>{
if(map.has(i)){
map.set(i,map.get(i)+1)
}else{
map.set(i,0)
}
}
====额外维护了一个map对象,可以不维护map,直接统计5美元和10美元数量