L oop через массив элементов Puppeteer и далее анализировать каждый из них - PullRequest
0 голосов
/ 09 мая 2020

Ой, я пытался работать с этим в течение долгого времени, и я так застрял.

Мне нужно пройти ряд объектов DOM и извлечь информацию из каждого с помощью селекторов XPath. Мой исходный код HTML не имеет никаких идентификаторов или классов для своих элементов, поэтому придется много ходить.

Вот несколько (очень упрощенный) пример кода. Цель состоит в том, чтобы получить список элементов 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']

(Да, я знаю, что могу выполнить sh задачу проще с этим образцом HTML. Но настоящий HTML, который я анализирую, безумно сложен. Это просто упрощенный взгляд на моя проблема.)

Код выше не работает, говоря, что у меня есть какая-то круговая ссылка на DOM. Я не могу понять, почему ... Я искал в Google ... Я даже не уверен, почему и как я использую eval () в одном месте, $ eval в другом, а затем я также прочитал об AssessmentHandler ... это так сбивает с толку.

1 Ответ

2 голосов
/ 09 мая 2020

Я не думаю, что вы можете использовать API Puppeteer внутри page.evaluate(): он выполняет свой код аргумента функции в чистом контексте браузера, поэтому попробуйте использовать здесь только веб-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' ] ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...