讲师中心 微信公众号
AI工具推荐 视频效率加速

Puppeteer自动化:处理动态密码键盘点击与XPath策略

陌婷姑娘_4128

陌婷姑娘_4128

发布时间:2025-11-07 19:09:23

|

755人浏览过

|

来源于php中文网

原创

Puppeteer自动化:处理动态密码键盘点击与XPath策略

在使用puppeteer进行自动化测试时,处理动态密码键盘这类非标准输入组件常遇到点击失效问题,表现为`node is either not clickable or not an htmlelement`错误。本教程将详细介绍如何通过将密码拆分为字符、利用xpath精确匹配键盘按键,并结合shift键处理大小写,从而有效解决此类复杂ui元素的交互挑战,确保自动化流程的稳定执行。

自动化动态密码键盘点击的挑战

在许多银行或安全敏感的网站中,为了提高安全性,会采用动态密码键盘(虚拟键盘)来代替传统的文本输入框。这种键盘的按键通常是动态渲染的HTML元素,它们的ID可能不固定,或者在页面加载后才出现。当尝试使用Puppeteer直接选择并点击这些元素时,可能会遇到以下问题:

  1. 元素未就绪: 在尝试点击时,元素可能尚未完全渲染或处于可交互状态。
  2. 元素选择不准确: 仅通过类名或部分ID可能无法唯一且稳定地选中特定按键。
  3. Node is either not clickable or not an HTMLElement错误: 这通常发生在Puppeteer试图点击一个实际上不可点击的元素(例如,它被其他元素遮挡,或者它不是一个可交互的HTML元素,如、

为了克服这些挑战,我们需要一种更精确、更健壮的元素选择和交互策略。

解决方案:XPath与字符级交互

核心解决方案在于结合以下策略:

  1. 字符级密码输入: 将密码分解为单个字符,逐个模拟点击键盘上的对应按键。
  2. XPath精确选择: 利用XPath的强大功能,根据元素的文本内容和类名来精确匹配动态键盘上的每个按键。
  3. 处理特殊按键: 对于大小写字母,需要模拟“Shift”键的按下和释放操作。
  4. 健壮的等待机制: 在每次交互前,确保目标元素已经加载并可点击。

1. 准备工作与基本设置

首先,确保您的项目中已安装Puppeteer。

Word 文档生成与编辑
Word 文档生成与编辑

需要创建、读取、编辑或处理 Word 文档(.docx / .dotx)时使用。触发词:'Word'、'word 文档'、'.docx'、'生成报告'、'制作合同/简历/方案/说明书'、'提取 word 内容'、'在文档里查找替换'、'给文档加页眉页脚/目录/表格'。也用于把任意内容排版成一份正式的 Word 文件。不要用它处理 PDF、Excel 或无关编程任务。中文创作场景尤其适合:小说大纲稿、投稿文档、合同、简历、工作总结。

下载
const puppeteer = require('puppeteer');

为了提高代码的可读性和复用性,我们可以创建一个辅助函数来封装“等待元素并点击”的常见操作。

// 辅助函数:等待元素出现并点击
async function waitClick(page, selector, isXPath = false) {
    let btn;
    if (isXPath) {
        // 使用page.waitForXPath等待XPath元素
        btn = await page.waitForXPath(selector, { visible: true, timeout: 5000 });
        // Puppeteer的XPath结果是ElementHandle数组,需要取第一个
        await btn.click();
    } else {
        // 使用page.waitForSelector等待CSS选择器元素
        btn = await page.waitForSelector(selector, { visible: true, timeout: 5000 });
        await btn.click();
    }
}

注意: 当使用XPath时,page.waitForXPath返回的是ElementHandle的数组,但click()方法通常直接作用于单个ElementHandle。如果XPath预期只匹配一个元素,可以直接在返回的ElementHandle上调用click()。如果waitClick函数需要通用,可以考虑page.waitForXPath返回的ElementHandle数组的第一个元素,或者直接使用page.click(selector)如果selector是XPath字符串且page.click支持。在上述修改后的waitClick中,为了简化,假设page.waitForXPath返回的btn是可直接点击的ElementHandle(这通常是正确的行为)。

2. 自动化登录流程

以下是完整的自动化登录函数,它将处理用户名输入、密码键盘交互和最终的登录提交。

const puppeteer = require('puppeteer');

// 辅助函数:等待元素出现并点击
async function waitClick(page, selector, isXPath = false) {
    let elementHandle;
    try {
        if (isXPath) {
            // 使用page.waitForXPath等待XPath元素,并确保可见
            const elements = await page.waitForXPath(selector, { visible: true, timeout: 10000 });
            // 如果XPath返回多个元素,通常我们希望点击第一个匹配项
            if (Array.isArray(elements) && elements.length > 0) {
                elementHandle = elements[0];
            } else {
                throw new Error(`XPath selector "${selector}" did not find any visible elements.`);
            }
        } else {
            // 使用page.waitForSelector等待CSS选择器元素,并确保可见
            elementHandle = await page.waitForSelector(selector, { visible: true, timeout: 10000 });
        }
        await elementHandle.click();
    } catch (error) {
        console.error(`Error clicking element with selector "${selector}" (isXPath: ${isXPath}):`, error);
        throw error; // 重新抛出错误以便上层捕获
    }
}

async function login(user, password) {
    let browser;
    try {
        browser = await puppeteer.launch({ headless: false, defaultViewport: null }); // 设置headless: false便于观察,defaultViewport: null防止默认视口裁剪
        const page = await browser.newPage();

        const url = 'https://ebanking.cpa-bank.dz/customer/';
        await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); // 等待网络空闲,确保页面完全加载

        // 1. 输入用户名
        await page.waitForSelector('#form\:username', { visible: true }); // 等待用户名输入框出现
        await page.type('#form\:username', user, { delay: 50 }); // 模拟人类输入,增加延迟

        // 2. 点击“下一步”或提交按钮
        await waitClick(page, '#form\:submit');

        // 3. 等待密码键盘区域加载
        await page.waitForSelector('body', { visible: true }); // 等待页面体加载完毕
        await waitClick(page, '#inputPassId'); // 点击密码输入区域,激活键盘

        // 4. 处理密码输入
        const passArr = [...password]; // 将密码字符串拆分为字符数组
        for (const char of passArr) {
            if (/[A-Z]/.test(char)) { // 如果字符是大写字母
                // 模拟按下Shift键
                await waitClick(page, "xpath/" + `//button[contains(@class,"keypad-key") and text()="Shift"]`, true);
                // 点击大写字母
                await waitClick(page, "xpath/" + `//button[contains(@class,"keypad-key") and text()="${char}"]`, true);
                // 模拟释放Shift键
                await waitClick(page, "xpath/" + `//button[contains(@class,"keypad-key") and text()="Shift"]`, true);
            } else {
                // 点击普通字符
                await waitClick(page, "xpath/" + `//button[contains(@class,"keypad-key") and text()="${char}"]`, true);
            }
        }

        // 5. 点击登录按钮 (根据实际页面调整选择器)
        // 示例中有一个显示密码的按钮,可能不需要点击,直接点击登录
        // await waitClick(page, '#form\:showPasswordId a'); // 如果有显示密码按钮,可能需要点击或跳过

        await waitClick(page, '#form\:loginButton'); // 点击最终的登录按钮

        console.log('登录流程执行完毕。');

        // 可以在这里添加一些断言来验证登录是否成功
        // 例如:await page.waitForSelector('.dashboard-element');

    } catch (error) {
        console.error('登录过程中发生错误:', error);
        throw error; // 重新抛出错误,方便外部调用者处理
    } finally {
        if (browser) {
            // await browser.close(); // 登录成功或失败后关闭浏览器
        }
    }
}

// 执行登录函数
(async () => {
    try {
        await login("96391281", "AadBaiudhw");
    } catch (error) {
        console.error('主程序捕获到错误:', error);
    }
})();

3. 代码解析与注意事项

  • puppeteer.launch({ headless: false, defaultViewport: null }): headless: false 允许您在浏览器中直观地看到自动化过程,这对于调试非常有用。defaultViewport: null 可以防止Puppeteer设置默认的视口大小,而是使用浏览器本身的默认大小,这在某些响应式网站上可能更自然。
  • page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }): waitUntil: 'networkidle2' 会等待页面加载完成且网络连接在500ms内没有超过2个请求,这通常比domcontentloaded或load更可靠,能确保所有资源(包括JS动态加载的内容)都已加载。timeout设置了页面导航的最大等待时间。
  • page.type(selector, text, { delay: 50 }): delay 参数模拟了人类打字的速度,这有助于规避一些反爬机制,并使自动化行为更自然。
  • waitClick(page, selector, isXPath) 辅助函数: 这个函数封装了等待元素可见并点击的逻辑,提高了代码的健壮性。
    • page.waitForSelector(selector, { visible: true, timeout: 10000 }):等待CSS选择器匹配的元素出现在DOM中并变得可见。
    • page.waitForXPath(selector, { visible: true, timeout: 10000 }):等待XPath选择器匹配的元素出现在DOM中并变得可见。
    • visible: true 是关键,它确保元素不仅存在于DOM中,而且用户可以看到并与之交互。
  • XPath 表达式 //button[contains(@class,"keypad-key") and text()="a"]:
    • //button:选择页面上所有的
    • contains(@class,"keypad-key"):筛选出class属性包含keypad-key的按钮。
    • text()="a":进一步筛选出其文本内容为"a"的按钮。
    • 这种组合方式可以非常精确地定位到动态键盘上具有特定文本内容的按键,即使它们的其他属性(如ID)是动态变化的。
  • [...password]: 这是一个ES6语法,用于将字符串转换为字符数组,方便遍历。
  • 处理大小写 (/[A-Z]/.test(char)): 通过正则表达式判断字符是否为大写字母。如果是,则在点击该字母前和后分别点击“Shift”键,模拟Shift键的按下和释放,以确保输入的是大写字符。
  • 错误处理与资源清理: 使用try...catch...finally结构来捕获可能发生的错误,并在finally块中确保浏览器实例被关闭,即使在发生错误的情况下也能释放资源。

总结

通过本教程,我们学习了如何使用Puppeteer有效处理动态密码键盘的自动化点击问题。关键在于:将复杂的输入分解为字符级操作,利用XPath进行精确且稳定的元素定位,并妥善处理特殊按键(如Shift)。这种方法不仅解决了Node is either not clickable or not an HTMLElement错误,也为自动化其他复杂的、非标准的用户界面元素提供了通用的策略。在实际应用中,务必根据目标网站的具体DOM结构调整CSS选择器和XPath表达式,并利用headless: false进行充分的调试。

热门AI工具

更多
蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

Flowith
Flowith Hot

Flowith是一款基于画布和智能体工作流的 AI 协作工作空间。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

4856

2023.06.20

正则表达式不包含
正则表达式不包含

正则表达式,又称规则表达式,,是一种文本模式,包括普通字符和特殊字符,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式的文本。php中文网给大家带来了有关正则表达式的相关教程以及文章,希望对大家能有所帮助。

3321

2023.07.05

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

9262

2023.07.05

java正则表达式匹配字符串
java正则表达式匹配字符串

在Java中,我们可以使用正则表达式来匹配字符串。本专题为大家带来java正则表达式匹配字符串的相关内容,帮助大家解决问题。

812

2023.08.11

正则表达式空格
正则表达式空格

正则表达式空格可以用“s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。本专题为大家提供正则表达式相关的文章、下载、课程内容,供大家免费下载体验。

520

2023.08.31

Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

693

2023.11.13

正则表达式空格如何表示
正则表达式空格如何表示

正则表达式空格可以用“s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。想了解更多正则表达式空格怎么表示的内容,可以访问下面的文章。

406

2023.11.17

正则表达式中如何匹配数字
正则表达式中如何匹配数字

正则表达式中可以通过匹配单个数字、匹配多个数字、匹配固定长度的数字、匹配整数和小数、匹配负数和匹配科学计数法表示的数字的方法匹配数字。更多关于正则表达式的相关知识详情请看本专题下面的文章。php中文网欢迎大家前来学习。

739

2023.12.06

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

0

2026.11.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn