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

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

总结

这样我们在本地开发过程中就不需要手动复制token,直接运行node login.js即可。

当然Puppeteer可以做很多事情,比如自动化测试、屏幕截图和生成 PDF、爬虫、性能测试、表单自动填写等等,更多API可以查看官网学习。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容