最近公司有个项目是基于
vue
开发的,但部分老页面是前后端不分离的;比如登录页面。由于后端也没有相关登录接口,所以每次在本地启动服务后,需要到测试环境登陆;然后手动复制几个cookie
粘贴到本地启动的页面中,整个过程比较繁;所以用node
写个脚本去简化一下流程。
优化前的流程
本地
npm run serve
启动服务登录测试环境
https://test.xxxx.com/login
打开调试,找到相关cookie,复制
打开本地启动的页面并打开调试;粘贴复制的cookie,刷新页面
优化过程
安装Puppeteer和readline
Puppeteer:
Puppeteer 是一个由 Google 开发的 Node.js 库,用于控制 headless 浏览器(无图形用户界面的浏览器)。它提供了一套高级的 API,允许开发者通过程序方式操控浏览器的行为,包括导航、表单提交、截图、生成 PDF 等功能。Puppeteer通常用于执行自动化测试、屏幕截图、搜索引擎爬虫等任务。在本例中,我们使用 Puppeteer 模拟用户登录过程,获取登录后的 Cookies。
readline:
readline 是 Node.js 内置的模块之一,提供了一个接口来从可读流(如
process.stdin
)读取数据。它通常用于从终端接收用户输入,使得我们可以以交互的方式与用户进行通信。在本例中,我们使用 readline 创建了一个接口,以便用户能够在终端中输入账号和密码。
这两个模块的结合使用使得我们可以通过 Puppeteer
控制浏览器完成登录,而 readline
则使得用户能够在终端中直接输入账号和密码。
安装并引入模块
npm i puppeteer@20.0.0
npm i readline
引入 puppeteer
、readline
和 fs
:
const puppeteer = require('puppeteer')
const readline = require('readline')
const fs = require('fs')
定义登录函数
我们定义一个名为 login
的异步函数,用于模拟用户登录和获取 cookies。
/**
* 登录
* @param {string} url 登录页面url
* @param {string} usernameSelector 登录页面用户名输入框的ID
* @param {string} passwordSelector 登录页面密码输入框的ID
* @param {string} username 账号
* @param {string} password 密码
*/
async function login(url, usernameSelector, passwordSelector, username, password) {
// ...
}
启动浏览器
在 login
函数中,使用 puppeteer.launch()
启动一个 headless 浏览器实例,然后通过page.goto
打开我们传入的url。
const browser = await puppeteer.launch({ headless: true })
const page = await browser.newPage()
await page.goto(url, { waitUntil: 'load' })
输入用户名和密码
使用 page.type()
模拟输入用户名和密码,其中第一个参数为输入框的选择器。登录完成后,我们再通过page.click
去点击登录按钮。
await page.type(usernameSelector, username)
await page.type(passwordSelector, password)
await page.click('#_btnLogin')
await page.waitForNavigation({ waitUntil: 'load' })
获取 Cookies
使用 page.cookies()
获取页面的 cookies,并将我们需要的token
提取出来。我们这里就随便以APITOKEN
和 bpmftoken
为例子;提取后我们就可以使用browser.close()
关闭浏览器。
const cookies = await page.cookies()
const tokens = {}
for (const cookie of cookies) {
cookie.name === 'APITOKEN' && (tokens.APITOKEN = cookie.value)
cookie.name === 'bpmftoken' && (tokens.bpmftoken = cookie.value)
}
browser.close()
写入Tokens到文件
将获取到的tokens
写入JSON
文件并关闭终端。
const tokenJSON = JSON.stringify(tokens, null, 2)
const filePath = './src/config/tokens.json'
fs.writeFile(filePath, tokenJSON, (err) => {
if (err) throw err
console.log('token已写入,请执行 npm run serve')
process.exit(1)
});
访问终端输入数据
使用 readline
模块创建一个接口,获取用户输入的账号和密码。
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
let username = null;
let password = null;
const url = 'https://xxxx..com/login'; //登录页面
const usernameSelector = '#_txtUid'; //用户名输入框ID
const passwordSelector = '#_txtPwd'; //密码输入框ID
rl.question('请输入账号:', (answer) => {
username = answer
rl.question('请输入密码:', (answer) => {
password = answer
rl.close()
login(url, usernameSelector, passwordSelector, username, password)
})
});
终端执行下面命令即可实现获取token。
node login.js
然后在项目中通过读取/src/config/tokens.json
中的内容去手动写入token
即可。
完整代码如下:
const puppeteer = require('puppeteer')
const readline = require('readline')
const fs = require('fs')
async function login(url, usernameSelector, passwordSelector, username, password) {
const browser = await puppeteer.launch({ headless: true })
const page = await browser.newPage()
try {
await page.goto(url, { waitUntil: 'load' })
try {
await page.type(usernameSelector, username)
await page.type(passwordSelector, password)
} catch (error) {
console.log(error)
}
await page.click('#_btnLogin')
await page.waitForNavigation({ waitUntil: 'load' })
console.log('登录成功')
await page.waitForTimeout(500)
const cookies = await page.cookies()
const tokens = {}
for (const cookie of cookies) {
cookie.name === 'APITOKEN' && (tokens.APITOKEN = cookie.value)
cookie.name === 'bpmftoken' && (tokens.bpmftoken = cookie.value)
}
await browser.close()
const tokenJSON = JSON.stringify(tokens, null, 2)
const filePath = './src/config/tokens.json'
fs.writeFile(filePath, tokenJSON, (err) => {
if (err) throw err;
console.log('token已写入, 请执行npm run serve')
process.exit(1)
})
} catch (error) {
console.error('Error:', error)
await browser.close()
process.exit(1)
}
}
let username = null;
let password = null;
const url = 'https://xxxx..com/login'; //登录页面
const usernameSelector = '#_txtUid'; //用户名输入框ID
const passwordSelector = '#_txtPwd'; //密码输入框ID
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('请输入账号(默认GP00164,直接回车): ', (answer) => {
username = answer || 'GP00164';
rl.question('请输入密码: (默认GP00164,直接回车)', (answer) => {
password = answer || 'Xxzx2023@123'
rl.close()
login(url, usernameSelector, passwordSelector, username, password)
})
})
总结
这样我们在本地开发过程中就不需要手动复制
token
,直接运行node login.js
即可。
当然
Puppeteer
可以做很多事情,比如自动化测试、屏幕截图和生成 PDF、爬虫、性能测试、表单自动填写等等,更多API可以查看官网学习。