javascript - 遍历 Puppeteer 元素数组并进一步解析每个元素
问题描述
哦,伙计,我已经尝试了很长时间,但我被困住了。
我需要遍历一系列 DOM 对象,并使用 XPath 选择器从每个对象中提取信息。我的源 HTML 在其元素上没有任何标识 ID 或类,因此需要大量步行。
这是一些(非常简化的)示例代码。目标是获取 LI 元素列表,然后在每个元素上使用更多选择器来提取跨度内的名称。
简化示例代码:(https://try-puppeteer.appspot.com/)
const html = '
<html> <ul>
<li>
<div> <span>Joe</span> </div>
</li>
<li>
<div> <span>Bob</span> </div>
</li>
</ul> </html>';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto( `data:text/html,${html}` );
// now wait for a sec for the list to be populated
let arrayOfNames = await page.evaluate( async ( page ) => {
let results = [];
let ulElements = await page.$x( '//ul' );
// strangely, I get back an object here, though shouldn't I get back an array?
console.log( 'Got list of UL elements: ', ulElements );
// loop through each item we found with selector above
ulElements.forEach( async ( item ) => {
let oneItem = await item.$x( '//li/div' );
name = oneItem.$eval( 'span', element => element.innerText );
console.log( 'We found ' + name );
results.push( name );
} );
return results;
}, page );
// if it worked, arrayOfNames = ['Joe', 'Bob']
(是的,我知道我可以使用这个示例 HTML 更轻松地完成任务。但是我正在解析的真正 HTML 非常复杂。这只是对我的问题的简化。)
上面的代码失败了,说我有某种循环 DOM 引用。我不知道为什么...我一直在谷歌搜索...我什至不确定为什么以及如何在一个地方使用 evaluate() ,在另一个地方使用 $eval ,然后我还阅读了有关 evaluateHandler ……太混乱了。
解决方案
我不认为你可以在里面使用 Puppeteer API page.evaluate()
:它在纯浏览器上下文中执行它的函数参数代码,所以在这里尝试只使用 Web API。以下是实现目标的两种等效方法(使用选择器和 XPath):
'use strict';
const html = `
<html> <ul>
<li>
<div> <span>Joe</span> </div>
</li>
<li>
<div> <span>Bob</span> </div>
</li>
</ul> </html>`;
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.goto(`data:text/html,${html}`);
const arrayOfNames = await page.evaluate(() => {
const results1 = Array.from(
document.querySelectorAll('ul li > div span'),
span => span.innerText,
);
const results2 = [];
const xpathList = document.evaluate(
'//ul//li/div//span',
document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null,
);
for (let i = 0; i < xpathList.snapshotLength; i++) {
results2.push(xpathList.snapshotItem(i).innerText);
}
return [results1, results2];
});
console.log(arrayOfNames);
await browser.close();
} catch (err) {
console.error(err);
}
})();
和两个相等的结果:
[ [ 'Joe', 'Bob' ], [ 'Joe', 'Bob' ] ]
推荐阅读
- prometheus - 如何在基于 sysdig 指标标签的 grafana 仪表板中创建下拉菜单
- java - 计算没有内置函数的数字的平方根(例如 Math.sqrt())
- angular - 如果条件为真以角度打开对话框
- laravel - Laravel 推送器在发送事件时面临 HMAC 错误
- javascript - 为解析器塑造数据
- pine-script - 在图上的策略中绘制每笔交易的利润
- python - 如何有效地比较来自不同数据框的两列?
- android - 按下时如何更改反应性TouchableOpacity颜色
- flutter - 抛出异常后 Flutter 无法捕获异常
- vba - MS Access - 将数据从子表单传递到另一个表单