puppeteer建立署理转发恳求

运用办法

tnpm install -g @ali/tuzki
tuzki set -a 你的账号
tuzki set -p 你的暗码
tuzki start

tuzki set

-a --account ,设置域账号
-p --passowrd ,设置域账号暗码

tuzki config

输出当时装备的域账号和暗码

tuzki start

运转署理,默许是 5000 端口,假如你在 start 后指定了一个端口则会在指定端口运转

tuzki start -p 9000 // 在9000端口运转

开发进程

koa

Koa 是一个新的 web 结构,由 Express 暗地的原班人马打造, 致力于成为 web 运用和 API 开发领域中的一个更小、更赋有表现力、更强健的柱石。 经过运用 async 函数,Koa 帮你丢掉回调函数,并有力地增强错误处理。 Koa 并没有绑缚任何中间件, 而是供给了一套高雅的办法,协助您快速而愉快地编写服务端运用程序。
当然,这段话是我抄的。https://koa.bootcss.com/

puppeteer

Puppeteer是一个Node库,它供给了高档API来经过DevTools协议操控Chrome或Chromium 。
当然,这句话也是我抄的。https://github.com/puppeteer/puppeteer。简略的说便是Puppeteer供给了一个可供node环境运用的一个无界面、代码操控的谷歌浏览器。能够经过调用api来完成一个用户或许有的一切操作。说实话我用完今后觉得这个拿来当爬虫用真的杠杠的。。

计划

基本是围绕着怎样生成cookie,怎样恳求接口进行。
让puppeteer替代用户登陆渠道,恳求接口,拿到呼应今后再用koa呼应本地的前端恳求。emm,大约便是下面这条线。
puppeteer建立署理转发恳求

代码完成

代码完成思路大致分两部分,榜首部分是让koa去辨认和呼应前端恳求,第二部分是puppeteer收到koa拆解出协议和参数后,收发恳求。

koa部分

用koa生成一个http server,开端监听某个端口的恳求。这儿运用了koa-log4协助记载日志。

const Koa = require("koa");
const log4js = require("koa-log4");
const logger = log4js.getLogger("app");
const { PORT } = require("./config");
require("../log");
const bodyParser = require("koa-bodyparser");
const { instance: lubanProxy } = require("./lubanProxy");
async function server() {
// init app & proxy
const app = new Koa();
app.use(bodyParser());
app.use(log4js.koaLogger(log4js.getLogger("http"), { level: "auto" }));
await lubanProxy.loginLuban();
// add logger to a request
app.use(async (ctx, next) => {
const start = new Date();
await next();
const ms = new Date() - start;
logger.info(`${start} ${ctx.method} ${ctx.url} - ${ms}ms`);
});
// send request to lb-test
app.use(async ctx => {
if (ctx.method === "GET") {
let res = await lubanProxy.get(ctx.url);
ctx.body = res;
} else if (ctx.method === "POST") {
let res = await lubanProxy.post(ctx.url, ctx.request.body);
ctx.body = res;
}
});
app.on("error", (err, ctx) => {
logger.error("server error", err, ctx);
});
app.listen(PORT);
}
server();

puppeteer部分

生成一个浏览器,登陆渠道,向koa供给get和post办法。

登陆部分

模仿实在用户的登陆操作即可。

loginLuban = async () => {
this.browser = await puppeteer.launch();
const page = await this.browser.newPage();
await page
.goto(
"https://login.abc.com/login.html“
)
.catch(async e => {
await page.waitFor(2000);
logger.error(`load login page timeout,retrying...`);
});
await page
.evaluate(() => {
document.querySelector("input[name='account']").focus();
})
.catch(async _ => {
logger.error(`Cannot get login form`);
});
await page.keyboard.type(ACCOUNT);
await page
.evaluate(() => {
document.querySelector("input[name='password']").focus();
})
.catch(async _ => {
logger.error(`Cannot get login form`);
});
await page.keyboard.type(PASSWORD);
await Promise.all([page.waitForNavigation(), page.click(".submit")])
.then(async () => {
await page.goto("http://luban.abc.net/manage.htm");
console.log("proxy ready...");
})
.catch(async _ => {
logger.error(
`Navigation timeout of 30000 ms exceeded,restarting browser...`
);
await this.restartBrowser();
});
};

get恳求

puppeteer只能用来模仿用户操作,无法自若的发送ajax,所以get恳求的思路是用page.goto来模仿。

get = async url => {
const page = await this.browser.newPage();
let res = "";
await page
.goto("http://luban.abc.net" + url)
.then(async () => {
res = await page.content();
res = res.slice(res.indexOf("{"), res.lastIndexOf("}") + 1);
})
.catch(_ => {
logger.error(`get request got net::ERR_CONNECTION_RESET error`);
res = {
code: -1,
message: "Got a net error, try again?"
};
});
await page.close();
return res;
};

post恳求

post恳求比get杂乱一些,由于get能够经过页面跳转,而post无法模仿。

  /**
* 用注入一段js的方法发送post恳求
* 翻开lb-test jarvis的index页面,一起注入一段js代码,将参数填充进js代码段中,
* 将接口回来的内容写入div#root的innerHTML中,wait()接口恳求时刻后,获取div#root的innerHTML即为接口回来内容。
* 为每个恳求独自拓荒一个标签页,避免上一个恳求没结束时即被新的恳求掩盖,
* 当恳求结束时自动封闭标签页,开释占用的内存
* 若此进程成功,则回来json字符串,若失利,回来失利原因
* @param {string} url 恳求的地址
* @param {object} param 恳求的参数
* @return {string} json字符串
*/
post = async (url, param) => {
const page = await this.browser.newPage();
let res = "";
await page.goto(
"http://lb-test.alibaba.net/project/jarvis/page/index.html"
);
await page.addScriptTag({
content: `
$.post('http://lb-test.alibaba.net'+'${url}', {data: ${JSON.stringify(
param.data
)}}, function (result) {
document.querySelector('#root').innerHTML  = JSON.stringify(result)
});`
});
await page.waitFor(500);
res = await page.evaluate(() => {
return document.querySelector("#root").innerHTML;
});
await page.close();
return res;
};