Puppeteer中如何精准选中同时含body-copy与custom-body-copy的类?
问题
需要在Puppeteer中精准选中同时拥有body-copy和custom-body-copy类的元素(页面存在数百个body-copy类元素),对应的HTML结构如下:
<div class="row item-row" id="1000017509" data-body-row="" automation-id="itemRows_17"> <div class="body-copy custom-body-copy" automation-id="itemNumberLabel_17"> Item 879520 </div> </div>
当前使用的代码如下:
const products = await page.$$('.item-row'); Promise.all(products.map(async product => { // 查找产品SKU、名称和价格 let productId = await product.$eval('.body-copy', el => el.innerText.trim().replace(/,/g, '').replace('Item', '').replace(/\s+/g, '')); // 如需产品名称,可使用:let productName = await product.$eval(".body-copy-link", el => el.innerText.trim().replace(/,/g,' -')); let productPrice = await product.$eval('.product_desc_txt div span', el => el.innerText.trim().replace(/,/g, '')); // 格式化为CSV行 return productId + ',' + productPrice + ','; })).then(lines => { // 写入文件 fs.writeFileSync("products.csv", lines.join('\n'), 'utf-8'); browser.close();
将选择器改为.body-copy.custom-body-copy时,会抛出错误Error: failed to find element matching selector "${selector}",但该选择器在document.querySelectorAll()中可正常使用,请问该如何解决?
解决方法
1. 处理部分父容器无目标元素的情况
代码遍历所有.item-row并在其中查找目标元素,但可能存在部分.item-row内部没有同时拥有两个类名的元素,导致$eval因找不到元素抛出错误。而控制台的document.querySelectorAll是全局查找,不会遍历每个父容器,因此不会触发该问题。
解决方式:
- 先尝试获取元素,存在再执行逻辑:
let productId = ''; const skuEl = await product.$('.body-copy.custom-body-copy'); if (skuEl) { productId = await skuEl.evaluate(el => el.innerText.trim().replace(/,/g, '').replace('Item', '').replace(/\s+/g, '')); }
- 或用
try/catch捕获错误:
let productId = ''; try { productId = await product.$eval('.body-copy.custom-body-copy', el => el.innerText.trim().replace(/,/g, '').replace('Item', '').replace(/\s+/g, '')); } catch (e) { console.log(`当前行找不到目标元素: ${e}`); // 可选择跳过当前项或设默认值 }
2. 等待动态元素加载完成
若页面为异步加载,执行page.$$('.item-row')时部分元素的类名可能还未更新为body-copy custom-body-copy,需增加等待逻辑:
// 等待至少一个目标元素加载完成 await page.waitForSelector('.item-row .body-copy.custom-body-copy'); const products = await page.$$('.item-row');
或在遍历每个父容器时等待内部元素:
await product.waitForSelector('.body-copy.custom-body-copy', { timeout: 3000 }); let productId = await product.$eval('.body-copy.custom-body-copy', el => el.innerText.trim().replace(/,/g, '').replace('Item', '').replace(/\s+/g, ''));
3. 更换选择器方式验证
若问题仍存在,可尝试其他选择器写法:
// 精确匹配类名顺序 await product.$eval('[class="body-copy custom-body-copy"]', el => ...); // 匹配包含指定类名的元素 await product.$eval('.body-copy[class*="custom-body-copy"]', el => ...);
内容的提问来源于stack exchange,提问作者jest3rz
相关产品推荐
相关产品推荐

