likes
comments
collection
share

用Puppeteer优化项目本地开发流程:一键获取登录Token

作者站长头像
站长
· 阅读数 21

最近公司有个项目是基于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

引入 puppeteerreadlinefs

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提取出来。我们这里就随便以APITOKENbpmftoken 为例子;提取后我们就可以使用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)
    })
})

总结

往期推荐