2014-09-09 13 views
23

Jestem za pomocą skrobania w Internecie za pomocą Node.js. Chciałbym użyć XPath, ponieważ mogę go wygenerować półautomatycznie z kilkoma rodzajami GUI. Problem polega na tym, że nie mogę znaleźć sposobu, aby to zrobić skutecznie.Wykonanie parsowania stron za pomocą Node.js i XPath

  1. jsdom jest bardzo wolny. Parsowanie pliku 500KiB zajmuje mniej więcej minutę z pełnym obciążeniem procesora i dużą ilością pamięci.
  2. Popularne biblioteki do analizowania HTML (np. cheerio) ani nie obsługują XPath, ani nie eksponują modelu DOM zgodnego z W3C.
  3. Efektywne analizowanie HTML jest oczywiście zaimplementowane w WebKit, więc używanie opcji phantom lub casper jest opcją, ale te wymagają uruchomienia w specjalny sposób, a nie tylko node <script>. Nie mogę liczyć na ryzyko wynikające z tej zmiany. Na przykład znacznie trudniej jest znaleźć node-inspector z phantom.
  4. Spooky to opcja, ale jest to buggy enough, więc nie uruchomiła się wcale na moim komputerze.

Jaki jest więc właściwy sposób analizy strony HTML za pomocą XPath?

+1

https://www.npmjs.org/package/xpath lub https://github.com/yaronn/xpath.js? – mb21

+0

@ mb21 Dowolna wydajna implementacja DOM, aby je uruchomić? –

Odpowiedz

29

Możesz to zrobić w kilku krokach.

  1. Analizowanie kodu HTML za pomocą parse5. Złą stroną jest to, że wynikiem nie jest DOM. Choć jest wystarczająco szybki i kompilacja W3C.
  2. Serialize to do XHTML z xmlserializer, który akceptuje DOM-podobne struktury parse5 jako dane wejściowe.
  3. Parsować ponownie XHTML z xmldom. Teraz masz wreszcie ten DOM.
  4. Biblioteka xpath opiera się na xmldom, umożliwiając uruchamianie zapytań XPath. Należy pamiętać, że XHTML ma swoją własną przestrzeń nazw, a zapytania takie jak //a nie będą działać.

W końcu coś takiego.

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); 
})(); 
+0

Dziękuję, działa idealnie. Poza tym musiałem zastąpić 'var document = parser.parse (html.toString());' od 'var document = parse5.parse (html.toString()); 'i pozbyć się linii' var parser = new parse5.Parser(); '(używając parse5 wersja 2.0.2) – qqilihq

1

Właśnie zacząłem używać npm install htmlstrip-native, który używa native implementation do parsowania i wyodrębniania odpowiednich części HTML. Twierdzi się, że jest 50 razy szybszy niż czysta implementacja js (nie zweryfikowałem tego twierdzenia).

W zależności od potrzeb można użyć htmlstrip bezpośrednio lub podnieść kod i wiązania, aby jesteś właścicielem C++ używane wewnętrznie w htmlstrip-rodzimej

Jeśli chcesz użyć XPath, a następnie użyć otoki już dostepne tutaj; https://www.npmjs.org/package/xpath

+0

0. Twój link jest uszkodzony. 1. Ta biblioteka analizuje obiekty i jest to dość oczywiste ze względu na jej nazwę. 2. XPath nie jest nawet wspomniany w twojej odpowiedzi. –

+0

Naprawiono zepsuty link; dodano link do implementacji xpath, z jakiego powodu nie znalazłeś/wykorzystałeś tego samodzielnie? – Soren

+0

Również wskazywał zły kod ... naprawiono ... – Soren

7

Libxmljs to obecnie najszybsza realizacja (coś like a benchmark), ponieważ jest to tylko wiązania do C-biblioteki LibXML który obsługuje XPath 1.0 Zapytania:

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

Jednak trzeba zdezynfekować swój HTML pierwszy i konwersji do właściwego XML. Aby to zrobić, możesz użyć narzędzia wiersza poleceń HTMLTidy (tidy -q -asxml input.html) lub jeśli chcesz zachować tylko węzeł, coś takiego jak xmlserializer powinno wystarczyć.

0

Być może nigdy nie będzie prawidłowej metody przetwarzania stron HTML. Pierwsza recenzja na temat skrobania i przeszukiwania stron internetowych pokazuje, że Scrapy może być dobrym kandydatem do Twoich potrzeb. Akceptuje selektory CSS i XPath. W kodzie Node.js mamy całkiem nowy moduł node-osmosis. Ten moduł jest zbudowany na libxmljs, więc ma obsługiwać zarówno CSS, jak i XPath, chociaż nie znalazłem żadnego przykładu przy użyciu XPath.

1

Myślę, że Osmosis jest tym, czego szukasz.

  • Używa rodzimy libxml C powiązania
  • Obsługuje CSS 3.0 i XPath hybrydy 1,0 selektor
  • selektorów Sizzle, Slick selektorów i więcej
  • Bez dużych zależności jak jQuery, cheerio lub jsdom
  • Funkcje parsera HTML:

    • Szybki parsin g
    • Bardzo szybkie wyszukiwanie
    • Małe zużycie pamięci
  • HTML DOM wyposażony

    • obciążenia i wyszukiwania Ajax zawartości
    • interakcji DOM i wydarzenia
    • Wykonaj osadzone i zdalnych skryptów
    • Kod egzekucyjny w DOM

Here's an example:

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