最近公司有个项目是基于vue开发的,但部分老页面是前后端不分离的;比如登录页面。由于后端也没有相关登录接口,所以每次在本地启动服务后,需要到测试环境登陆;然后手动复制几个cookie粘贴到本地启动的页面中,整个过程比较繁;所以用node写个脚本去简化一下流程。
优化前的流程
优化过程
安装 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.0npm 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'; //用户名输入框IDconst passwordSelector = '#_txtPwd'; //密码输入框ID
rl.question('请输入账号:', (answer) => { username = answer rl.question('请输入密码:', (answer) => { password = answer rl.close() login(url, usernameSelector, passwordSelector, username, password) })});
复制代码
终端执行下面命令即可实现获取 token。
然后在项目中通过读取/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'; //用户名输入框IDconst 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 可以查看官网学习。
评论