Оставьте только элементы с текстом и удалите все остальные элементы

Я пытаюсь очистить веб-сайт, используя Puppeteer и Cheerio. Я получил HTML-код страницы, которую хочу очистить с помощью puppeteer. Я загрузил этот HTML-код в Cheerio.

async function run() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  const html = await get_to_page_with_required_source_code(page);
  const $ = cheerio.load(html);
  await browser.close();
}

run();

Сейчас я хочу удалить из HTML все элементы, не содержащие текста. Ниже приведен пример.

<div class = "abc">
    <img src = "..." />
</div>
<div class = "def">
    <div class = "jkl">
        <span class = "ghi">This is a text</span>
    </div>
    <div class = "mno">This is another text</div>
</div>

Вывод приведенного выше HTML должен быть:

<span class = "ghi">This is a text</span>
<div class = "mno">This is another text</div>

поскольку это единственные два элемента, содержащие текст.

Как я могу это сделать?

Пожалуйста, покажите нам, что вы пробовали

Carsten Løvbo Andersen 10.06.2024 08:49

вам необходимо уточнить, как обрабатывать вложенные и встроенные элементы.

GTK 10.06.2024 17:53
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если можете, попробуйте реализовать это в JavaScript:

if (element.innerText.trim() != "") {
    // element has content
} else {
    // element is empty
}

Это очень-очень широкий ответ.

Carsten Løvbo Andersen 10.06.2024 08:55

Это не работает, потому что практически все элементы имеют .innerHTML, включая любые закрывающие теги других элементов, в которых есть HTML, включая все тело. Все, что ему соответствует, это что-то вроде <p></p>, но даже если бы это было то, чего хотел ОП, все равно недостаточно кода, чтобы это произошло.

ggorlen 10.06.2024 15:56
Ответ принят как подходящий

Во-первых, вообще не совмещайте Puppeteer и Cheerio. Либо сайт является динамическим, и в этом случае используйте Puppeteer и работайте напрямую с действующим DOM (используйте jQuery, если вам нравится синтаксис Cheerio), либо, если сайт статический, используйте только fetch и Cheerio и пропустите медлительность Puppeteer.

Вот один из способов сделать это с помощью Cheerio (вы можете добавить fetch для запроса данных, если это статический сайт):

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

const html = `
<div class = "abc">
    <img src = "..." />
</div>
<div class = "def">
    <div class = "jkl">
        <span class = "ghi">This is a text</span>
    </div>
    <div class = "mno">This is another text</div>
</div>`;

const $ = cheerio.load(html);
const textEls = [...$("*")]
  .filter(e => $(e).children().length === 0 && $(e).text().trim())
  .map(e => $.html($(e)));
console.info(textEls);

Вот как это сделать с помощью Puppeteer:

const puppeteer = require("puppeteer"); // ^22.10.0

const html = `<Same as above>`;

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html, {waitUntil: "domcontentloaded"});
  const textEls = await page.$$eval("*", els =>
    els
      .filter(e => e.children.length === 0 && e.textContent.trim())
      .map(e => e.outerHTML)
  );
  console.info(textEls);
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

Вывод в обоих случаях одинаков (вы можете добавить .join("\n"), если хотите, чтобы вывод был строкой именно такой, как вы ее опубликовали):

[
  '<span class = "ghi">This is a text</span>',
  '<div class = "mno">This is another text</div>'
]

Имейте в виду: это немного странное желание, поэтому может быть, есть лучший способ достичь того, чего вы действительно пытаетесь достичь.

Другие вопросы по теме