使用Puppeteer爬取HTML列表时无法获取指定元素值的问题
问题:Puppeteer爬取HTML列表时无法获取指定元素值
问题详情
尝试使用Puppeteer从HTML列表提取字符串,可成功爬取第一个div内的前两个p元素,但始终无法获取第二个div中值为“3 st”的p元素。调整CSS选择器、添加延时均无效,怀疑是选择器使用错误。
目标HTML结构
<button class="css-4od5c4 e1ttybed2"> <div class="css-1tkalz1 e3whs8q0"> <p class="css-iqfm9l enp2lf70">Sisjön</p> <p class="css-1cwtvfm enp2lf70">Askim</p> <div class="css-7omsg3 e3whs8q0"> <p class="css-1n26c6q enp2lf70">Välj butik</p> </div></div> <div class="css-177ui4i e3whs8q0"> <p class="css-iqfm9l enp2lf70">3 st</p></div> </button> <button class="css-4od5c4 e1ttybed2"> <div class="css-1tkalz1 e3whs8q0"> <p class="css-iqfm9l enp2lf70">random address...</p> <p class="css-1cwtvfm enp2lf70">some city...</p> <div class="css-7omsg3 e3whs8q0"> <p class="css-1n26c6q enp2lf70">Välj butik</p> </div></div> <div class="css-177ui4i e3whs8q0"> <p class="css-iqfm9l enp2lf70">3 st</p></div> </button>
原代码
//Wait for list to stores to load then map store content await page.waitForSelector('.css-4od5c4'); const storesData = await page.evaluate(async () => { await new Promise((resolve) => setTimeout(resolve, 5000)); const stores = Array.from(document.querySelectorAll('.css-4od5c4 .css-1tkalz1')); const data = stores.map((item) => { const address = item.querySelector('.css-1tkalz1 .css-iqfm9l').textContent.trim(); const city = item.querySelector('.css-1tkalz1 .css-1cwtvfm').textContent.trim(); const amountElement = item.querySelector('.css-177ui4i.e3whs8q0 p.css-iqfm9l.enp2lf70'); const amount = amountElement ? amountElement.textContent.trim() : 'no value'; return { address, city, amount }; }); return data; }); console.log(storesData)
当前返回结果
[ { address: 'random address...', city: 'some city...', amount: 'no value' }, { address: 'random address...', city: 'some city...', amount: 'no value' }, ]
期望结果
[ { address: 'random address...', city: 'some city...', amount: '3 st' }, { address: 'random address...', city: 'some city...', amount: '3 st' }, ]
问题原因与解决方案
核心错误
- 选择器范围错误:原代码中
stores选中的是.css-4od5c4 .css-1tkalz1(每个按钮下的第一个div),但目标数量元素所在的.css-177ui4i是和.css-1tkalz1同级的元素(都属于按钮节点),因此在item(即.css-1tkalz1元素)内部无法找到.css-177ui4i元素。 - 冗余选择器:获取地址和城市时,
item本身就是.css-1tkalz1元素,选择器无需重复添加.css-1tkalz1前缀。
修正后的代码
await page.waitForSelector('.css-4od5c4'); const storesData = await page.evaluate(() => { // 直接选中每个按钮元素,而非按钮内的子div const stores = Array.from(document.querySelectorAll('.css-4od5c4')); const data = stores.map((item) => { // 从按钮内的信息div中提取地址和城市 const infoContainer = item.querySelector('.css-1tkalz1'); const address = infoContainer.querySelector('.css-iqfm9l').textContent.trim(); const city = infoContainer.querySelector('.css-1cwtvfm').textContent.trim(); // 从按钮内的数量div中提取数值 const amountElement = item.querySelector('.css-177ui4i .css-iqfm9l'); const amount = amountElement ? amountElement.textContent.trim() : 'no value'; return { address, city, amount }; }); return data; }); console.log(storesData);
额外优化说明
- 移除了
page.evaluate内部的setTimeout:page.waitForSelector('.css-4od5c4')已经确保所有按钮元素加载完成,无需额外延时等待。 - 简化了选择器逻辑,避免冗余前缀,提升代码可读性。
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

