新闻中心

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

2025-11-07
浏览次数:
返回列表

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。

const puppeteer = require('puppeteer');

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

火龙果写作 火龙果写作

用火龙果,轻松写作,通过校对、改写、扩展等功能实现高质量内容生产。

火龙果写作 277 查看详情 火龙果写作
// 辅助函数:等待元素出现并点击
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进行充分的调试。

以上就是Puppeteer自动化:处理动态密码键盘点击与XPath策略的详细内容,更多请关注其它相关文章!


# 的是  # 网站快速推广技巧视频  # seo简单易学  # 网站seo推广平台  # 网站推广后台托管公司  # 辽阳网站建设排名选哪家  # 提高百度搜索关键词排名  # 优化网站软件联系y火24星惠  # 罗湖seo策略  # seo都要了解什么  # 彩票网站运营推广策划书  # 抛出  # 自定义  # 弹出  # 出现在  # 按下  # css  # 第一个  # 加载  # 选择器  # html元素  # css选择器  # ai  # 浏览器  # 正则表达式  # go  # node  # js  # html  # word  # es6 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: win11 Snap Layouts怎么用 Win11窗口布局与分屏多任务高效指南【必学】  c++中的const_cast和reinterpret_cast怎么用_c++四种类型转换  steam官方网页快速访问 steam账号注册全流程  J*aScript中在Map循环中检测并处理空数组元素  yy漫画网页版官方入口_yy漫画官网登录页面链接  TikTok评论显示延迟如何处理 TikTok评论刷新优化方法  俄罗斯Yandex免登录入口_Yandex搜索引擎官网一键直达  Go语言JSON解析深度指南:动态访问与结构体映射实践  腾讯QQ邮箱登录入口_QQ邮箱官方网站使用地址  如何使用J*aScript精确选择并批量修改特定父元素下子链接的样式  铁路12306卧铺选择攻略 铁路12306下铺座位预定技巧  特斯拉自动驾驶房车计划曝光 原型车将于2027年亮相  大象笔记网页版入口 印象笔记网页版登录入口  如何创建独立于主系统的J*a运行环境_隔离式环境搭建策略  UC浏览器如何安装插件 UC浏览器添加扩展程序详细教程【进阶】  UC浏览器网页版登录入口官网 电脑版网址入口  深入理解字体排版:Adobe光学字偶距与CSS字偶距的差异与实现  b站怎么删除评论_b站评论管理与删除操作  c++如何使用chrono库处理时间_c++标准库时间与日期操作  CSS子选择器:如何区分并样式化嵌套列表的子层级  抖音DOU+怎么投最有效 抖音付费推广的ROI提升技巧  照顾宝贝2小游戏免费秒玩入口  LINUX下如何进行磁盘分区_fdisk与parted工具在LINUX中的使用对比  双系统安装时,如何设置默认启动系统? msconfig命令了解一下!  Win10如何清理注册表垃圾 Win10手动清理无效注册表【技巧】  CSS Flexbox如何实现多行排列_flex-wrap wrap自动换行显示  Win11怎么查看显卡显存 Win11显示适配器属性及专用视频内存查询  天猫2025双十一0点秒杀攻略 天猫爆款抢购时间  j*a toString()的覆盖  迅雷下载到U盘速度很慢怎么办_迅雷U盘下载慢优化方法  LINUX的perf命令入门_LINUX官方性能分析工具的使用与解读  Win11怎么开启高性能模式_Windows 11电源计划优化设置  深入理解J*a链表中的IPosition接口与使用  葱吃多了会怎样 葱吃多了会伤胃吗  Safari自带网页翻译功能怎么用 无需插件轻松看懂外文网站【方法】  DLsite中文平台入口 DLsite官网内容在线查看  火狐浏览器占用内存高卡顿怎么办 火狐浏览器性能优化设置技巧  J*aScript Promise链中如何正确终止后续.then执行并处理错误  Mudbox图层蒙版怎么用_Mudbox图层蒙版数字雕刻应用技巧  2025-2030年全球乘用车销量预测:新能源成增长主力  AI泡沫首次被“刺破”:GPU十年都无法存活!  写好的html代码怎么运行出来_运行写好的html代码方法【教程】  Win11怎么查看电脑配置_Win11硬件配置检测工具使用  Steam官网入口直达 Steam注册及登录步骤  抖音网页版快捷访问 抖音网页版网页版入口操作教程  QQ邮箱在线使用入口 QQ邮箱个人账号网页版登录  美团外卖商家服务中心入口 美团商家版官网入口  顺丰快件物流信息 官方网站查询入口  Gmail邮箱申请注册直达_Gmail邮箱免费注册PC版官网入口2025  Log4j Console Appender性能瓶颈与高并发优化策略 

搜索