Puppeteer无法获取页面DOM元素实时值问题求助
Puppeteer点击按钮后DOM值更新但获取不到最新值的问题
问题描述
我正在试用Puppeteer,遇到一个问题:编写了两个函数,一个用于点击按钮增加购物车商品数量,另一个用于获取点击后应更新的页面DOM元素值。点击按钮后,浏览器中能看到DOM元素值已更新,但通过button.evaluate()获取的结果却和未点击时一致。
我在第一个函数中两次获取值:一次是DOM元素的初始值,另一次是点击后的预期值(应比初始值大1),问题就出在这个流程里。
已尝试方案
- 使用
anElementHandle.evaluateHandle(),但似乎访问的是DOM快照 - 最初使用
anElementHandle.evaluate()方法 - 用
page.evaluate()手动选择输入框
个人想法
我猜测可以通过刷新页面获取新值,但这方法繁琐且没必要,希望了解底层原理来解决问题。
版本信息
- Puppeteer版本:22.7.0
- Node版本:20.12.2 LTS
相关代码
增加购物车数量的函数
async function increaseItemInCartByOne(plusButton: ElementHandle, shoppingCartAPI: any) { try { const previousAmount = await shoppingCartAPI.cartItemAmountNumberByButton(plusButton) while (true) { const [_, response] = await Promise.all([ plusButton.click(), page?.waitForResponse(r => r.request().url().includes('/cesta/') && r.request().method() === "PUT") ]) if (response?.status() === 200) { const currentAmount = await shoppingCartAPI.cartItemAmountNumberByButton(plusButton) if (currentAmount === previousAmount) { const message = await getUIWarningMessage(4000) as string const outOfStock = message?.search(/lo sentimos no puede llevar la cantidad solicitada/i) >= 0 if (outOfStock) { throw new Error("This item is now out of stock") } else throw new Error("Don't know what's happening") } else if (currentAmount > previousAmount) break; } } } catch (error) { console.log(error) } }
购物车操作API函数
async function shoppingCartAPI() { await gotoCartMenu() const productItemRows = await page?.$$(".table-row.prod-item-info") if (!productItemRows) throw new Error("Shopping Cart is probably empty. Aborting") return { cartItemAmountNumberByButton: async (button: ElementHandle) => { const updatedValue = await page?.evaluate((button) => button.previousElementSibling?.getAttribute("value")?.trim(), button); const newUpdatedValue = await page?.evaluate(() => { const newValue = document.querySelector(".table-row.prod-item-info:nth-child(2) .btn.cart-plus-btn") console.log(newValue) console.log(newValue?.previousElementSibling?.getAttribute("value")) return newValue?.previousElementSibling?.getAttribute("value")?.trim() }); return Number(updatedValue) }, getBuyAnotherItemInCartButtons: async () => { const buttons = [] for (const row of productItemRows) { buttons.push( (await row.evaluateHandle((productRow) => { const btn = productRow.querySelector(".btn.cart-plus-btn") return btn })).asElement() ) } if (buttons.length !== productItemRows.length) logger.error(`There are ${productItemRows.length} product(s) in cart and ${buttons.length} buttons for adding items are missing. This is weird`) return buttons } } }
解决方案
核心问题分析
- 误用
getAttribute("value"):输入框的实时值存在input.value属性中,getAttribute("value")仅返回HTML上的初始属性值,不会同步更新。 - 未等待DOM完成更新:仅等待PUT请求响应不足以确保页面DOM已完成渲染,可能存在前端异步更新的延迟。
- 冗余的硬编码查询:
cartItemAmountNumberByButton中第二个page.evaluate硬编码选择第二行按钮,与传入的目标按钮无关,属于无效代码。
具体修复步骤
- 修正值获取方式:将
getAttribute("value")替换为input.value,获取实时值:
cartItemAmountNumberByButton: async (button: ElementHandle) => { const updatedValue = await button.evaluate(btn => { const input = btn.previousElementSibling; return input?.value?.trim(); // 用value属性获取实时值 }); return Number(updatedValue); }
- 等待DOM值完成更新:在获取新值前,添加等待逻辑确保值已变化:
// 在点击响应成功后,先等待值变化再获取 if (response?.status() === 200) { // 等待输入框值与初始值不同 await page?.waitForFunction( (btn, prevVal) => btn.previousElementSibling?.value !== prevVal, {}, plusButton, previousAmount.toString() ); const currentAmount = await shoppingCartAPI.cartItemAmountNumberByButton(plusButton); // 后续逻辑不变 }
- 移除冗余代码:删除
cartItemAmountNumberByButton中硬编码查询第二行按钮的代码,避免干扰结果。
内容的提问来源于stack exchange,提问作者d3vr10
相关产品推荐
相关产品推荐

