web-dev-qa-db-de.com

Performantes Parsen von Seiten mit Node.js und XPath

Ich beschäftige mich mit Node.js im Web. Ich möchte XPath verwenden, da ich es mit verschiedenen GUI-Arten halbautomatisch generieren kann. Das Problem ist, dass ich keinen Weg finden kann, dies effektiv zu tun.

  1. jsdom ist extrem langsam. Es analysiert in einer Minute eine 500-KB-Datei mit voller CPU-Last und einem hohen Speicherbedarf.
  2. Beliebte Bibliotheken für die HTML-Analyse (z. B. cheerio) unterstützen weder XPath noch stellen sie W3C-kompatible DOMs bereit.
  3. Ein effektives HTML-Parsing ist natürlich in WebKit implementiert. Die Verwendung von phantom oder casper wäre eine Option, die jedoch auf besondere Weise ausgeführt werden muss, nicht nur node <script>. Ich kann mich nicht auf das mit dieser Änderung verbundene Risiko verlassen. Zum Beispiel ist es viel schwieriger zu finden, wie node-inspector mit phantom ausgeführt wird.
  4. Spooky ist eine Option, aber es ist fehlerhaft genug , so dass es überhaupt nicht auf meinem Rechner lief.

Was ist der richtige Weg, um eine HTML-Seite mit XPath zu analysieren?

26
polkovnikov.ph

Sie können dies in mehreren Schritten tun.

  1. HTML-Code mit parse5 analysieren. Der schlechte Teil ist, dass das Ergebnis nicht DOM ist. Obwohl es schnell genug und W3C-kompatibel ist.
  2. Serialisieren Sie es in XHTML mit xmlserializer, das DOM-ähnliche Strukturen von parse5 als Eingabe akzeptiert.
  3. Parsen Sie diese XHTML erneut mit xmldom. Jetzt hast du endlich das DOM.
  4. Die xpath-Bibliothek baut auf xmldom auf, sodass Sie XPath-Abfragen ausführen können. Beachten Sie, dass XHTML über einen eigenen Namespace verfügt und Abfragen wie //a nicht funktionieren.

Zum Schluss bekommst du so etwas.

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);
})();
32
pda

Libxmljs ist derzeit die schnellste Implementierung (etwas wie ein Benchmark ), da es nur Bindungen an die LibXML C-Bibliothek gibt, die XPath 1.0-Abfragen unterstützt:

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

Sie müssen jedoch zunächst Ihren HTML-Code bereinigen und in korrektes XML konvertieren. Dazu können Sie entweder das Befehlszeilenhilfsprogramm HTMLTidy (tidy -q -asxml input.html) verwenden. Wenn Sie jedoch nur Knoten erhalten möchten, sollte etwas wie xmlserializer den Trick ausführen.

11
mb21

Ich habe gerade damit angefangen, npm install htmlstrip-native zu verwenden, das eine native Implementierung verwendet, um die relevanten HTML-Teile zu analysieren und zu extrahieren. Es wird behauptet, 50 Mal schneller zu sein als die reine js-Implementierung (ich habe diese Behauptung nicht bestätigt).

Je nach Ihren Anforderungen können Sie html-strip direkt verwenden oder den Code und die Bindungen heben, um eigenes C++ zu erstellen, das intern in htmlstrip-native verwendet wird

Wenn Sie xpath verwenden möchten, verwenden Sie den Wrapper, der hier bereits verfügbar ist: https://www.npmjs.org/package/xpath

1
Soren

Ich denke, Osmose ist was Sie suchen.

  • Verwendet native libxml C-Bindungen
  • Unterstützt CSS 3.0- und XPath 1.0-Auswahlhybriden
  • Sizzle-Selektoren, Slick-Selektoren und mehr
  • Keine großen Abhängigkeiten wie jQuery, Cheerio oder Jsdom
  • HTML-Parser-Funktionen

    • Schnelles Parsen
    • Sehr schnelles Suchen
    • Kleiner Speicherbedarf
  • HTML-DOM-Funktionen

    • Laden und Suchen von Ajax-Inhalten
    • DOM-Interaktion und Ereignisse
    • Ausführen von eingebetteten und Remote-Skripts
    • Führen Sie den Code im DOM aus

Hier ist ein Beispiel:

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

Es gibt möglicherweise keinen richtigen Weg, um HTML-Seiten zu parsen. Eine erste Rezension zum Thema Web Scraping und Crawlen zeigt, dass Scrapy ein guter Kandidat für Ihre Bedürfnisse sein kann. Es akzeptiert sowohl CSS- als auch XPath-Selektoren. Im Bereich Node.js haben wir ein ziemlich neues Modul Node-Osmosis . Dieses Modul ist auf libxmljs aufgebaut, so dass es CSS und XPath unterstützen soll, obwohl ich mit XPath kein Beispiel gefunden habe.

0
pateheo