一、神奇的国度
puppeteer是一个谷歌的无头浏览器插件,他可以做很多事情,爬虫,运行js脚本,截取网页生成图片,自动化测试等等,这里我主要使用运行js脚本,获取一个加密后的返回值,为什么要写这篇文章呢?也是业务的需求,爬虫的哥们破解不掉一个关键性的参数,于是这个光荣而伟大的任务到了我们前端手里,不废话了,为了年终奖,开干...
ps:爬虫有风险,慎重
[api参考地址](https://www.kancloud.cn/luponu/puppeteer/870133)
二、初始化Nodejs
我是使用egg.js去做的,为啥用它?因为傻瓜。。。哈哈哈,直接运行下面命令去生成项目:
| ```
$ mkdir puppeteer && cd puppeteer $ npm init egg --type=simple $ npm i
``` |
| ----------------------------------------------------------------------------------- |
启动项目:
| ```
$ npm run dev $ open http://localhost:7001
``` |
| --------------------------------------------------
三、无脑装包
先增加白名单和跨域配置
我们首先在config设置文件下新增config.default.js和config.prod.js,内容可直接把默认的config.local.js的拷贝过来,这里主要去配置一些本地开发的信息和上线的信息,因为我使用了一个静态页面去加载了一个脚本,所以我这里配置了两个上线的地址,我这里直接给出相关配置项
config.default.js配置
const config = exports = {
// 跨域配置白名单
security: {
csrf: {
enable: false,
ignoreJSON: true,
},
domainWhiteList: [ '*' ], // 配置白名单
},
cors: {
origin: '*', // 允许所有跨域访问
credentials: true, // 允许 Cookie 跨域跨域
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
},
};
config.local.js配置
const userConfig = {
htmlUrl:'http://127.0.0.1:8899/public/index.html', // 根据自己需求自行更改
};
config.prod.js配置
const userConfig = {
htmlUrl:'http://xxxxx/public/index.html', // 根据自己需求自行更改
};
在app文件夹下面拷贝进去我们的静态页面和脚本
后面我们需要用node打开这个页面,调用里面的js函数去执行逻辑,获取到我们需要的东西
装包
// 执行
npm install --save puppeteer
四、逻辑开发提供接口
分析:我们需要打开预先准备的静态页面,然后执行页面上面的函数,才能获取到需要的参数,这里我们首先在router.js下面写出接口,然后在controller.js下编写逻辑
router.js代码如下:
router.post('/getxb', controller.home.getxb);
controller.js代码如下:
// 获取xb加密参数
async getxb() {
const { ctx } = this;
const data = await ctx.helper.puppeteer(this)
if(data){
ctx.body = {
code:'Success',
data:data,
msg:'成功'
};
ctx.status=200
}else{
ctx.body = {
code:'error',
data:null,
msg:'系统繁忙'
};
ctx.status=500
}
}
我这里把核心逻辑入到了extend下面的helper.js中
helper.js代码如下:
const puppeteer = require('puppeteer');
let browser=null,page=null;
exports.puppeteer = async (that) => {
//创建一个Browser浏览器实例,并设置相关参数
const { ctx } = that;
const {xb} = ctx.request.body;
if(!browser){
browser = await puppeteer.launch({
headless: true, // 是否以 无头模式 运行浏览器。默认是 true
defaultViewport: null,// 为每个页面设置一个默认视口大小。默认是 800x600。如果为 null 的话就禁用视图口。
// timeout: 0, // 等待浏览器实例启动的最长时间(以毫秒为单位)。默认是 30000 (30 秒). 通过 0 来禁用超时。
ignoreHTTPSErrors: true, // 是否在导航期间忽略 HTTPS 错误. 默认是 false
args: [
'--no-sandbox',
],
});
// 创建一个Page实例
page = await browser.newPage();
// 这里容易踩坑习惯上我们可能直接下传我们的参数,这样是不行的,因为这是我们的node环境,参数需要传递到我们静态页面所以我挂在了url上面
await page.goto(`${that.config.htmlUrl}?xb=${xb}`);
}
//执行原生Js方法
return await page.evaluate(() => {
return window.byted_acrawler.getxb(window.location.href.split('?')[1],null);
})
}
exports.closepuppeteer = async (that) => {
//调用此接口时关闭窗口
const { ctx } = that;
if(browser){
await browser.close();
browser=null;
page=null;
return '成功'
}else{
return null
}
}
ps:为什么变量声明在了外面这里是考虑到效率的问题,因为频繁的发开关闭窗口非常耗时间,这里是提供个接口给比人用所以我只打开了一次,后续所有的调用都在这里完成,下面我还写了一个关闭窗口的接口。
五、postman试试吧
我们带我们需要的参数试一下,可以看到拿到了我们需要的参数
ok,快来试试这个神迹吧!!!