Анализ синтаксического анализа страниц с помощью 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?
Ответы
Ответ 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.