使用Puppeteer对接MSAL登录时输入密码后脚本卡住如何解决
问题解决方案
核心问题原因
- 代码中
Promise.all等待导航的写法错误,提前await了点击操作,导致导航触发后才开始监听跳转,大概率触发超时卡住 - 提交密码前没有等待提交按钮从禁用状态变为可点击状态,MSAL的密码提交按钮默认是
disabled,输入密码后前端校验完成才会激活,直接点击禁用状态的按钮不会有任何响应,符合你描述的无网络、无控制台活动的表现 - 没有添加MSAL反自动化检测的绕过配置,微软的登录页面会检测自动化控制的浏览器,拦截表单提交请求
- 点击密码提交按钮后没有等待页面跳转,就直接查询下一步的"保持登录"按钮,元素未加载就会触发超时
修复后的可运行代码
const puppeteer = require('puppeteer'); const msal = async () => { // 启动浏览器时添加反检测配置 const browser = await puppeteer.launch({ headless: false, args: ['--disable-blink-features=AutomationControlled'], ignoreDefaultArgs: ['--enable-automation'] }); const page = await browser.newPage(); // 移除webdriver标识规避检测 await page.evaluateOnNewDocument(() => { Object.defineProperty(navigator, 'webdriver', { get: () => false }); }); await page.goto('https://testurl.com'); // 修正登录按钮点击+导航等待的写法 await page.waitForSelector('#login-btn', { visible: true }); const loginButton = await page.$('#login-btn'); await Promise.all([ page.waitForNavigation(), // 先注册导航监听,再执行点击 loginButton.click() ]); // 输入邮箱 await page.waitForSelector('#i0116', { visible: true }); const emailInput = await page.$('#i0116'); await emailInput.type('testuser@hello.com'); const submitButton = await page.$('#idSIButton9'); await Promise.all([ page.waitForNavigation(), submitButton.click() ]); // 输入密码 await page.waitForSelector('#i0118', { visible: true }); const passwordInput = await page.$('#i0118'); await passwordInput.type('password123'); // 等待密码提交按钮变为可点击状态 await page.waitForSelector('#idSIButton9:not([disabled])', { visible: true }); const submitButton2 = await page.$('#idSIButton9'); await Promise.all([ page.waitForNavigation(), // 等待提交密码后的跳转 submitButton2.click() ]); // 等待保持登录状态的按钮加载完成且可点击 await page.waitForSelector('#idSIButton9:not([disabled])', { visible: true }); const submitButton3 = await page.$('#idSIButton9'); await Promise.all([ page.waitForNavigation(), // 等待跳转回业务站点 submitButton3.click() ]); await page.waitForSelector('#welcome-banner-title-h2', { visible: true }); // 校验登录结果 if (page.url() !== 'https://testurl.com') { console.error('login failed!'); } else { console.log('login succeeded'); } await browser.close(); } msal();
关键修改说明
- 启动浏览器时添加了反自动化检测参数,避免MSAL拦截自动化登录请求
- 修正了所有
Promise.all监听导航的写法,先注册导航监听再执行点击操作,避免漏掉导航事件导致超时 - 提交密码前新增了按钮可用状态等待,确保点击的是可交互的按钮
- 每一步按钮点击都配套了导航等待,确保页面跳转完成后再执行后续操作
- 补全了变量声明,避免全局变量污染引发的未知错误
内容的提问来源于stack exchange,提问作者chris
相关产品推荐
相关产品推荐

