Как я могу получить селекторы CSS для элемента по значению в NodeJS?

Я пишу веб-скребок с Node и рассматриваю возможность использования модуля, такого как Cheerio или JSDom, для анализа HTML в DOM для набора URL-адресов. Однако у меня есть конкретная функциональность, которая необходима.

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

Чтобы уточнить, есть ли на сайте три страницы, каждая из которых содержит разные продукты:

Страница 1:

<html>
<body>
<h1>Product 1</h1>
<p>Desc</p>
<small>$2.05</small>
</body>
</html>

Страница 2:

<html>
<body>
<h1>Product 2</h1>
<p>Desc</p>
<small>$8.05</small>
</body>
</html>

Страница 3:

<html>
<body>
<h1>Product 3</h1>
<p>Desc</p>
<small>$5.07</small>
</body>
</html>

Скажем, у меня уже есть данные для первого продукта (я знаю название продукта, описание и цену). Я хочу получить селекторы каждого из этих элементов, используя первую страницу, а затем использовать эти селекторы для очистки данных с других страниц.

Учитывая содержимое тега в DOM, как я могу получить селектор CSS для этого элемента? Например:

<html>
  <body>
    <h1>Hello world</h1>
  </body>
</html>

Как я могу предоставить Cheerio/JSDom строку типа «Hello world» и вернуть селектор CSS в DOM, где находится элемент?

Есть ли простой способ сделать это (в том числе с использованием другого фреймворка) или единственный способ просто перебрать весь объект DOM и проверить значения каждого элемента по отдельности?


person Chandler Freeman    schedule 25.01.2017    source источник
comment
Будет несколько разных XPath, возвращающих один и тот же список узлов. Какой вы хотите? Я предполагаю, что //*[text()='Hello world'] это не то, что вам нужно?   -  person OrangeDog    schedule 25.01.2017
comment
Что вы хотите узнать? Поскольку у вас мог бы быть такой же простой XPath, как //*[. = "Hello world"]   -  person skAstro    schedule 25.01.2017
comment
Все, что я хочу, это найти элемент/путь, где находится элемент, содержащий привет, мир, чтобы я мог использовать этот путь для извлечения другой информации позже. По сути, я автоматически строю свою модель парсинга, используя начальные данные.   -  person Chandler Freeman    schedule 25.01.2017
comment
А что, если совпадающих узлов больше, чем один?   -  person OrangeDog    schedule 25.01.2017
comment
Затем просто получите путь первого. Является ли XPATH лучшим способом сделать это? Просто ищу общее руководство о самом простом способе решения проблемы.   -  person Chandler Freeman    schedule 25.01.2017


Ответы (1)


Это проще и эффективнее всего выполнить с помощью модели SAX, но ее можно применить и к обходу DOM. вместо.

var match, path = [];

parser.on('start', function(tag) { currentPath.push(tag); });
parser.on('end', function(tag) { currentPath.pop(); });

parser.on('text', function(text) {
  if (!match && text === 'Hello world') {
    match = path.join('/');
  }
});

Если вам все равно нужно построить DOM, вы можете использовать XPath для поиска узла (который внутренне просто зацикливает весь DOM), а затем зацикливает родителей.

var path = [];
var node = document.xpath('//*[.="Hello world"]')[0];

do { 
  path.push(node.tag);
} while (node = node.parent);

var match = path.reverse().join('/');

Этот второй метод намного более неэффективен, особенно если вам нужно найти много разных узлов. Метод SAX может покрыть их все за один проход, но может столкнуться с искаженным вводом в зависимости от реализации синтаксического анализатора.

Для селекторов CSS замените '/' на ' > '.

person OrangeDog    schedule 25.01.2017
comment
В вашем первом предложении, что такое объект парсера? Не могли бы вы предоставить более полный обзор того, что делает ваш код? - person Chandler Freeman; 25.01.2017
comment
Это парсер SAX. Предположительно какой-то Stream, через который вы можете передать ответ, или EventEmitter, через который вы можете запустить DOM. - person OrangeDog; 25.01.2017
comment
Я только что изменил свой вопрос, чтобы вместо этого спросить о селекторах CSS. Ваше решение SAX все еще применимо? - person Chandler Freeman; 25.01.2017
comment
@ChandlerFreeman Тот факт, что вы не можете сказать, говорит о том, что вы на самом деле не знаете, что хотите делать. - person OrangeDog; 25.01.2017