循环遍历Puppeteer元素的数组,然后进一步解析每个元素

时间:2020-05-09 13:23:49

标签: 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引用。我不知道为什么...我一直在谷歌搜索...我什至不知道为什么以及如何在一个地方使用评价(),在另一个地方使用$ eval,然后我还阅读了关于evaluateHandler的信息。 ……太混乱了。

1 个答案:

答案 0 :(得分:2)

我认为您不能在(node:83046) UnhandledPromiseRejectionWarning: Error: Page crashed! (node:83046) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:83046) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. 内使用Puppeteer API:它在纯浏览器上下文中执行其函数自变量代码,因此请尝试在此处仅使用Web API。这是两种等效的方法(使用选择器和XPath)来实现您的目标:

page.evaluate()

还有两个相等的结果:

'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);
  }
})();