Подтвердить что ты не робот

Анализ синтаксического анализа страниц с помощью Node.js и XPath

Я использую веб-скребок с Node.js. Я бы хотел использовать XPath, поскольку я могу генерировать его полуавтоматически с несколькими видами графического интерфейса. Проблема в том, что я не могу найти способ сделать это эффективно.

  • jsdom очень медленный. Он разбор 500KiB файла через минуту или около того с полной загрузкой процессора и большим объемом памяти.
  • Популярные библиотеки для разбора HTML (например, cheerio) не поддерживают XPath и не предоставляют DOM, совместимый с W3C.
  • Эффективный синтаксический анализ HTML, очевидно, реализован в WebKit, поэтому использование опции phantom или casper будет вариантом, но для этого нужно работать специальным образом, а не только node <script>. Я не могу полагаться на риск, связанный с этим изменением. Например, гораздо труднее найти, как запустить node-inspector с помощью phantom.
  • Spooky - это вариант, но он достаточно глючит, так что он вообще не запускался на моей машине.

Каков правильный способ анализа HTML-страницы с помощью XPath?

4b9b3361

Ответ 1

Вы можете сделать это несколькими шагами.

  • Разбор HTML с parse5. Плохая часть заключается в том, что результатом не является DOM. Хотя это достаточно быстро и W3C-compiant.
  • Сериализуйте его в XHTML с помощью xmlserializer, который принимает DOM-подобные структуры parse5 в качестве входных данных.
  • Разберите этот XHTML снова с помощью xmldom. Теперь у вас наконец есть DOM.
  • Библиотека xpath основывается на xmldom, что позволяет вам настраивать запросы XPath. Имейте в виду, что XHTML имеет собственное пространство имен, а запросы типа //a не будут работать.

Наконец, вы получите что-то вроде этого.

const fs = require('mz/fs');
const xpath = require('xpath');
const parse5 = require('parse5');
const xmlser = require('xmlserializer');
const dom = require('xmldom').DOMParser;

(async () => {
    const html = await fs.readFile('./test.htm');
    const document = parse5.parse(html.toString());
    const xhtml = xmlser.serializeToString(document);
    const doc = new dom().parseFromString(xhtml);
    const select = xpath.useNamespaces({"x": "http://www.w3.org/1999/xhtml"});
    const nodes = select("//x:a/@href", doc);
    console.log(nodes);
})();

Ответ 2

Libxmljs в настоящее время является самой быстрой реализацией (что-то как эталонный тест), поскольку это только привязки к LibXML C-library, которая поддерживает запросы XPath 1.0:

var libxmljs = require("libxmljs");
var xmlDoc = libxmljs.parseXml(xml);
// xpath queries
var gchild = xmlDoc.get('//grandchild');

Однако вам нужно сначала дезинформировать свой HTML-код и преобразовать его в правильный XML. Для этого вы можете использовать утилиту командной строки HTMLTidy (tidy -q -asxml input.html), или если вы хотите сохранить node - только что-то вроде xmlserializer должен сделать трюк.

Ответ 3

Я только начал использовать npm install htmlstrip-native, который использует встроенную реализацию для анализа и извлечения соответствующих частей html. Он утверждает, что он в 50 раз быстрее, чем чистая реализация js (я не подтвердил это требование).

В зависимости от ваших потребностей вы можете напрямую использовать html-strip или поднять код и привязки, чтобы вы сами использовали С++ внутри htmlstrip-native

Если вы хотите использовать xpath, используйте здесь уже обернутую оболочку;  https://www.npmjs.org/package/xpath

Ответ 4

Я думаю, Osmosis - это то, что вы ищете.

  • Использует собственные привязки libxml C
  • Поддержка гибридных селекторов CSS 3.0 и XPath 1.0
  • Селекторы Sizzle, селектор Slick и многое другое
  • Никаких больших зависимостей, таких как jQuery, cheerio или jsdom
  • Функции парсера HTML

    • Быстрый парсинг
    • Очень быстрый поиск
    • Малая занимаемая площадь памяти
  • Особенности HTML DOM

    • Загрузка и поиск содержимого ajax
    • Взаимодействие с DOM и события
    • Выполнение встроенных и удаленных сценариев
    • Выполнить код в DOM

Вот пример:

osmosis.get(url)
    .find('//div[@class]/ul[2]/li')
    .then(function () {
        count++;
    })
    .done(function () {
        assert.ok(count == 2);
        assert.done();
    });

Ответ 5

Невозможно правильно проанализировать HTML-страницы. Самый первый обзор веб-соскабливания и обхода показывает мне, что Scrapy может быть хорошим кандидатом для ваших нужд. Он принимает как селектор CSS, так и XPath. В области Node.js мы имеем довольно новый модуль node-osmosis. Этот модуль построен на libxmljs, так что он должен поддерживать как CSS, так и XPath, хотя я не нашел никакого примера с помощью XPath.