如何用Puppeteer判断Ajax返回的查询结果或无记录提示?
解决Puppeteer中Ajax返回结果的判断问题
嘿,这个场景我太熟悉了——用try-catch嵌套waitForSelector确实既难调试又不够优雅,尤其是超时时间设置得不对的时候,要么等太久要么提前报错。给你几个更靠谱的解决方案,应该能解决你的问题:
方法一:用waitForFunction自定义判断逻辑
这是我最常用的方法,它允许你直接在页面上下文里编写判断条件,等待任意一个目标元素出现,之后再明确区分是哪种情况。
// 先定义你的两个目标选择器 const SELECTOR_RESULTS = "SELECTOR1"; // 查询结果的选择器 const SELECTOR_NO_RECORDS = "SELECTOR2"; // "No records found"的选择器 // 等待页面上出现任意一个目标元素 await page.waitForFunction( (sel1, sel2) => document.querySelector(sel1) || document.querySelector(sel2), { timeout: 10000 }, // 全局超时时间,可根据实际情况调整 SELECTOR_RESULTS, SELECTOR_NO_RECORDS // 传递给页面函数的参数 ); // 现在判断到底是哪种情况 const hasResults = await page.$(SELECTOR_RESULTS) !== null; if (hasResults) { console.log("查询到结果,开始处理..."); // 这里写处理查询结果的逻辑,比如提取数据 } else { console.log("没有找到记录"); // 处理无记录的逻辑 }
这个方法的优势在于:
- 逻辑清晰,调试时能直接看到等待的条件,不会像try-catch那样混淆“超时错误”和“无记录”的情况
- 不需要设置多个零散的超时,全局超时统一管理
- 只要其中一个元素出现就会继续执行,效率更高
方法二:监听Ajax请求的响应(更高效)
如果你知道查询对应的Ajax接口,可以直接监听这个请求的响应,在DOM渲染之前就知道结果,这比等待DOM元素更高效可靠。
// 先监听目标Ajax请求,根据接口URL的特征匹配 const responsePromise = page.waitForResponse((response) => response.url().includes("/your-query-api-endpoint") // 替换成实际的接口URL标识 ); // 触发表单提交操作(比如点击提交按钮) await page.click("#submit-button"); // 替换成你的提交按钮选择器 // 获取接口响应 const response = await responsePromise; const responseData = await response.json(); // 如果响应是JSON格式,否则用response.text() // 根据响应内容直接判断结果 if (responseData.records?.length > 0) { // 有结果,等待结果DOM渲染完成 await page.waitForSelector(SELECTOR_RESULTS); // 处理查询结果 } else { // 无记录,等待提示DOM出现 await page.waitForSelector(SELECTOR_NO_RECORDS); // 处理无记录情况 }
这个方法适合接口逻辑稳定的场景,避免了依赖DOM结构变化的风险,而且能提前获取结果,节省等待DOM渲染的时间。
方法三:用Promise.race同时等待两个选择器
如果你更习惯用waitForSelector,可以用Promise.race让两个选择器的等待同时进行,哪个先触发就走对应的逻辑:
const resultsPromise = page.waitForSelector(SELECTOR_RESULTS); const noRecordsPromise = page.waitForSelector(SELECTOR_NO_RECORDS); try { // 等待任意一个选择器出现 await Promise.race([resultsPromise, noRecordsPromise]); } catch (err) { // 处理超时情况(比如两个元素都没出现) console.error("等待超时,未找到任何目标元素"); } // 再判断具体是哪种情况 const hasResults = await page.$(SELECTOR_RESULTS) !== null; // 后续处理逻辑和方法一一致
不过这个方法需要注意:如果其中一个选择器永远不会出现,对应的waitForSelector会抛出超时错误,导致Promise.race失败,所以最好配合全局超时处理,或者确保页面最终一定会出现其中一个元素。
内容的提问来源于stack exchange,提问作者Jon Wilson
相关产品推荐
相关产品推荐

