Сглаживание вложенного массива заголовков и нескольких дочерних элементов в Cheerio

Используя Cheerio, мне нужно выполнить итерацию на нескольких уровнях для доступа к элементам. Как я могу использовать вложенную итерацию для доступа к элементам и возврата массива объектов? В настоящее время мой код из-за вложенного цикла возвращает массив массивов объектов.

HTML:

<body style = "overflow: hidden">
    <div class = "cookie-box"></div>
    <div id = "next">
        <div></div>
        <div>
            <main id = "main">
                <article>
                    <div>
                       <h2>title</h2>
                    </div>
                    <div></div>
                    <div class = "layout">
                        <form></form>
                        <section aria-labelledby = "Train">
                          <ul>
                            <li>
                               <p>title</p>
                               <span>
                                 <a>
                                    <span>123</span>
                                 </a>
                                 <a>
                                   <span>456</span>
                                 </a>
                                 ...
                               </span>
                              ...
                           </li>
                           <li></li>
                           ...
                      </ul>
                   </section>
                    </div>
                </article>
            </main>
        </div>
    </div>
</body>

код:

const data = [...$('[aria-labelledby = "Train"] li')].map(e => { 
return [...$item.find('span a')].map(elem=> {
  return {
     p: $(e).find("p").text(),
     number: $(elem).find('span').text()
  }
})

});

что я хотел бы в качестве вывода:

[
  {
    p: "title",
    num: 123
  },
  {
    p: "title",
    num: 456
  }
]

что я получаю:

[
 [
  {
    p: "title",
    num: 123
  },
  {
    p: "title",
    num: 456
  }
 ]
]

🤔 А знаете ли вы, что...
С JavaScript можно создавать интерактивные формы и проверять введенные пользователем данные.


1
58
1

Ответ:

Решено

Вы можете использовать flatMap, чтобы удалить этот уровень вложенности:

const cheerio = require("cheerio"); // ^1.0.0-rc.12

const html = `
<section aria-labelledby = "Train">
  <ul>
    <li>
      <p>title</p>
      <span>
        <a>
          <span>123</span>
        </a>
        <a>
          <span>456</span>
        </a>
      </span>
    </li>
  </ul>
</section>`;

const $ = cheerio.load(html);
const data = [...$('[aria-labelledby = "Train"] li')].flatMap(li =>
  [...$(li).find("span a")].map(a => ({
    p: $(li).find("> p").text().trim(),
    number: $(a).text().trim(),
  }))
);
console.info(data);

Другой подход, позволяющий удалить вложенный цикл, — перебрать внутренние элементы и использовать .closest() для возврата к контейнеру элемента списка и поиска заголовка:

const data = [...$('[aria-labelledby = "Train"] li span a')].map(
  a => ({
    p: $(a).closest("li").find("> p").text().trim(),
    number: $(a).text().trim(),
  })
);

Это нарушает одно из моих практических правил парсинга веб-страниц: «работайте сверху вниз, а не снизу вверх», но в данном случае оба кажутся вполне приемлемыми. Подход «снизу вверх» может оказаться запутанным, как только вам понадобится больше элементов из контейнера или в тех случаях, когда родительский элемент может неожиданно измениться. Если вы обнаружите, что несколько раз тянетесь вверх к разным элементам, подумайте о том, чтобы вернуться к подходу сверху вниз.

См. Очистка таблицы с заголовком слияния и теги cherijs select, которые не находятся внутри другого указанного тега, где приведены более сложные примеры выравнивания вложенного массива в Cheerio.