Screen Scraping mit Node.js

Sie haben NodeJS möglicherweise als Webserver verwendet, aber wussten Sie, dass Sie es auch für das Web-Scraping verwenden können? In diesem Lernprogramm erfahren Sie, wie Sie statische Webseiten - und solche nervigen mit dynamischen Inhalten - mithilfe von NodeJS und ein paar hilfreichen NPM-Modulen durchsuchen.



Ein bisschen über das Web-Scraping

Web-Scraping war in der Welt der Web-Entwicklung schon immer eine negative Konnotation - und das aus gutem Grund. In der modernen Entwicklung sind APIs für die meisten gängigen Dienste vorhanden und sollten eher zum Abrufen von Daten als zum Verschrotten verwendet werden. Das inhärente Problem beim Scraping besteht darin, dass es auf der visuellen Struktur der zu scrapierenden Seite beruht. Immer wenn sich dieser HTML-Code ändert - egal wie klein die Änderung auch sein mag - kann dies Ihren Code vollständig beschädigen.

Trotz dieser Mängel ist es wichtig, etwas über das Web-Scraping und einige der verfügbaren Tools zu lernen, um diese Aufgabe zu unterstützen. Wenn auf einer Website keine API oder Syndication-Feeds (RSS / Atom usw.) angezeigt werden, bleibt nur noch die Möglichkeit, diesen Inhalt zu erhalten.

Hinweis: Wenn Sie die erforderlichen Informationen nicht über eine API oder einen Feed abrufen können, ist dies ein gutes Zeichen dafür, dass der Eigentümer nicht möchte, dass auf diese Informationen zugegriffen werden kann. Es gibt jedoch Ausnahmen.


Warum NodeJS verwenden??

Schaber können wirklich in jeder Sprache geschrieben werden. Der Grund, warum ich Node gerne nutze, liegt in seiner asynchronen Natur, was bedeutet, dass mein Code an keiner Stelle im Prozess blockiert wird. Ich bin mit JavaScript ziemlich vertraut, das ist also ein zusätzlicher Bonus. Schließlich gibt es einige neue Module, die für NodeJS geschrieben wurden und die das problemlose Scrapfen von Websites erleichtern (gut, so zuverlässig wie Scraping sein kann!). Lass uns anfangen!


Einfaches Scraping mit YQL

Beginnen wir mit dem einfachen Anwendungsfall: statischen Webseiten. Dies sind Ihre Standard-Webseiten. Für diese, Yahoo! Query Language (YQL) sollte die Arbeit sehr gut machen. Für diejenigen, die mit YQL nicht vertraut sind, handelt es sich um eine SQL-ähnliche Syntax, die verwendet werden kann, um mit verschiedenen APIs auf konsistente Weise zu arbeiten.

YQL bietet einige großartige Tabellen, mit denen Entwickler HTML aus einer Seite herausholen können. Die, die ich hervorheben möchte, sind:

  • html
  • data.html.cssselect
  • htmlstring

Lassen Sie uns die einzelnen Elemente durchgehen und prüfen, wie Sie sie in NodeJS implementieren können.

html Tabelle

Das html tabelle ist die grundlegendste Möglichkeit, HTML von einer URL zu entfernen. Eine regelmäßige Abfrage mit dieser Tabelle sieht folgendermaßen aus:

Wählen Sie * aus HTML aus, wobei URL = "http://finance.yahoo.com/q?s=yhoo" und xpath = "// div [@ id =" yfi_headlines "] / div [2] / ul / li / a "

Diese Abfrage besteht aus zwei Parametern: dem "URL" und dem "Xpath". Die URL ist selbsterklärend. Der XPath besteht aus einem XPath-String, der YQL mitteilt, welcher Abschnitt des HTML-Codes zurückgegeben werden soll. Versuchen Sie diese Abfrage hier.

Zusätzliche Parameter, die Sie verwenden können, schließen ein Browser (boolean), Zeichensatz (String) und Comp (string). Ich musste diese Parameter nicht verwenden, verweise jedoch auf die Dokumentation, wenn Sie spezielle Anforderungen haben.

Mit XPath nicht vertraut?

Leider ist XPath kein sehr beliebter Weg, um die HTML-Baumstruktur zu durchlaufen. Für Anfänger kann das Lesen und Schreiben kompliziert sein.

Schauen wir uns die nächste Tabelle an, die dasselbe tut, aber stattdessen CSS verwenden kann

data.html.cssselect Tabelle

Das data.html.cssselect table ist meine bevorzugte Methode, um HTML von einer Seite zu entfernen. Es funktioniert genauso wie das html Tabelle, ermöglicht jedoch CSS anstelle von XPath. In der Praxis konvertiert diese Tabelle das CSS in XPath unter der Haube und ruft dann die html Tisch, so ist es etwas langsamer. Der Unterschied sollte für das Abkratzen von Bedürfnissen vernachlässigbar sein.

Eine regelmäßige Abfrage mit dieser Tabelle sieht folgendermaßen aus:

Wählen Sie * aus data.html.cssselect aus, wo url = "www.yahoo.com" und css = "# news a"

Wie Sie sehen, ist es viel sauberer. Ich empfehle, dass Sie diese Methode zuerst ausprobieren, wenn Sie versuchen, HTML mit YQL zu kratzen. Versuchen Sie diese Abfrage hier.

htmlstring Tabelle

Das htmlstring Tabelle ist nützlich, wenn Sie versuchen, einen großen Teil des formatierten Texts von einer Webseite zu entfernen.

Wenn Sie diese Tabelle verwenden, können Sie den gesamten HTML-Inhalt dieser Seite in einer einzelnen Zeichenfolge abrufen und nicht als JSON, der basierend auf der DOM-Struktur aufgeteilt wird.

Zum Beispiel eine reguläre JSON-Antwort, die eine tag sieht so aus:

"results": "a": "href": "…", "target": "_blank", "content": "Apple Chief Executive Cook muss auf einer neuen Bühne klettern"

Sehen Sie, wie die Attribute als Eigenschaften definiert werden. Stattdessen die Antwort von der htmlstring Tabelle würde so aussehen:

"Ergebnisse": "Ergebnis": "Apple Chief Executive Cook steigt auf einer neuen Stufe auf

Warum sollten Sie das verwenden? Aus meiner Erfahrung ist dies von großem Nutzen, wenn Sie versuchen, eine große Menge formatierten Textes zu kratzen. Betrachten Sie zum Beispiel den folgenden Ausschnitt:

Lorem ipsum dolor sitzen amet, consectetur adipiscing elit.

Proin nec diam magna. Sed non lorem ein nisi porttitor pharetra et non arcu.

Mit der htmlstring In der Tabelle können Sie diesen HTML-Code als Zeichenfolge abrufen und die HTML-Tags mit regex entfernen, sodass nur noch Text angezeigt wird. Dies ist einfacher als das Durchlaufen von JSON, das basierend auf der DOM-Struktur der Seite in Eigenschaften und untergeordnete Objekte aufgeteilt wurde.


Verwenden von YQL mit NodeJS

Nun, da wir uns mit einigen der in YQL verfügbaren Tabellen auskennen, implementieren wir einen Web-Scraper, der YQL und NodeJS verwendet. Glücklicherweise ist dies dank der node-yql Modul von Derek Gathright.

Wir können das Modul mit installieren npm:

npm install yql

Das Modul ist extrem einfach und besteht aus nur einer Methode: der YQL.exec () Methode. Es ist wie folgt definiert:

Funktion exec (String-Abfrage [, Funktionsrückruf] [, Objektparameter] [, Objekt httpOptions])

Wir können es verwenden, indem wir es anfordern und anrufen YQL.exec (). Nehmen wir zum Beispiel an, wir wollen die Schlagzeilen aller Posts auf der Nettuts-Hauptseite abkratzen:

var YQL = erfordern ("yql"); new YQL.exec ('select * from data.html.cssselect wobei url = "http://net.tutsplus.com/" und css = ". post_title eine" "- Funktion (Antwort) // Antwort enthält JSON dass du analysieren kannst);

Das Tolle an YQL ist die Fähigkeit, Ihre Abfragen zu testen und festzustellen, welche JSON-Daten Sie in Echtzeit erhalten. Rufen Sie die Konsole auf, um diese Abfrage auszuprobieren, oder klicken Sie hier, um den Roh-JSON anzuzeigen.

Das Params und httpOptions Objekte sind optional. Parameter können Eigenschaften wie enthalten env (ob Sie eine bestimmte Umgebung für die Tabellen verwenden) und Format (XML oder Json). Alle Eigenschaften übergeben in Params sind URI-codiert und werden an die Abfragezeichenfolge angehängt. Das httpOptions Objekt wird in den Header der Anforderung übergeben. Hier können Sie festlegen, ob Sie beispielsweise SSL aktivieren möchten.

Die JavaScript-Datei mit dem Namen yqlServer.js, enthält den minimalen Code, der zum Abkratzen mit YQL erforderlich ist. Sie können es ausführen, indem Sie in Ihrem Terminal den folgenden Befehl eingeben:

Knoten yqlServer.js

Ausnahmen und andere bemerkenswerte Werkzeuge

YQL ist meine bevorzugte Wahl, um Inhalte von statischen Webseiten zu entfernen, da sie einfach zu lesen und zu verwenden ist. YQL schlägt jedoch fehl, wenn die betreffende Webseite eine robots.txt Datei, die eine Antwort darauf ablehnt. In diesem Fall können Sie einige der unten aufgeführten Dienstprogramme anzeigen oder PhantomJS verwenden, die wir im folgenden Abschnitt behandeln werden.

Node.io ist ein nützliches Node-Dienstprogramm, das speziell für das Daten-Scraping entwickelt wurde. Sie können Jobs erstellen, die Eingaben entgegennehmen, sie verarbeiten und einige Ausgaben zurückgeben. Node.io wird auf Github gut beobachtet und enthält einige hilfreiche Beispiele, um den Einstieg zu erleichtern.

JSDOM ist ein sehr beliebtes Projekt, das den W3C DOM in JavaScript implementiert. Bei der Bereitstellung von HTML kann ein DOM erstellt werden, mit dem Sie interagieren können. Lesen Sie in der Dokumentation nach, wie Sie JSDOM und eine beliebige JS-Bibliothek (z. B. jQuery) verwenden können, um Daten von Webseiten zu kratzen.


Scraping von Seiten mit dynamischem Inhalt

Bisher haben wir uns einige Tools angesehen, die uns dabei helfen können, Webseiten mit statischem Inhalt zu kratzen. Mit YQL ist es relativ einfach. Leider werden oft Seiten angezeigt, deren Inhalt dynamisch mit JavaScript geladen wird. In diesen Fällen ist die Seite anfangs häufig leer, und der Inhalt wird anschließend angefügt. Wie können wir mit diesem Problem umgehen??

Ein Beispiel

Lassen Sie mich ein Beispiel dafür geben, was ich meine. Ich habe eine einfache HTML-Datei auf meine eigene Website hochgeladen, die über JavaScript zwei Sekunden nach dem Anhängen einige Inhalte anfügt document.ready () Funktion wird aufgerufen. Sie können die Seite hier auschecken. So sieht die Quelle aus:

   Testseite mit angehängtem Inhalt nach dem Laden der Seite   Der Inhalt dieser Seite wird nach dem Laden der Seite an das DOM angehängt. 

Lassen Sie uns nun versuchen, den Text im Textfeld zu kratzen

unter Verwendung von YQL.

var YQL = erfordern ("yql"); new YQL.exec ('select * from data.html.cssselect wobei url = "http://tilomitra.com/repository/screenscrape/ajax.html" und css = "# content"', Funktion (Antwort) // Dies wird undefined zurückgeben! Das Scraping war nicht erfolgreich! Console.log (response.results););

Sie werden feststellen, dass YQL zurückkehrt nicht definiert weil, wenn die Seite geladen wird, die

ist leer. Der Inhalt wurde noch nicht angehängt. Sie können die Abfrage hier selbst ausprobieren.

Schauen wir uns an, wie wir dieses Problem umgehen können!

Geben Sie PhantomJS ein

PhantomJS kann Webseiten laden und einen Webkit-basierten Browser ohne GUI nachahmen.

Meine bevorzugte Methode, um Informationen von diesen Websites zu entfernen, ist die Verwendung von PhantomJS. PhantomJS beschreibt sich selbst als "headless Webkit mit einer JavaScript-API". Vereinfacht ausgedrückt bedeutet dies, dass PhantomJS Webseiten laden und einen Webkit-basierten Browser ohne GUI nachahmen kann. Als Entwickler können wir spezifische Methoden aufrufen, die PhantomJS zur Verfügung stellt Ausführen von Code auf der Seite Da das Skript sich wie ein Browser verhält, werden Skripts auf der Webseite wie in einem normalen Browser ausgeführt.

Um Daten von unserer Seite zu erhalten, verwenden wir PhantomJS-Node, ein großartiges kleines Open-Source-Projekt, das PhantomJS mit NodeJS verbindet. Unter der Haube führt dieses Modul PhantomJS als Kindprozess aus.

PhantomJS installieren

Bevor Sie das PhantomJS-Node NPM-Modul installieren können, müssen Sie PhantomJS installieren. Das Installieren und Erstellen von PhantomJS kann jedoch etwas schwierig sein.

Gehen Sie zuerst zu PhantomJS.org und laden Sie die entsprechende Version für Ihr Betriebssystem herunter. In meinem Fall war es Mac OSX.

Nach dem Download entpacken Sie es an einem Ort wie / Anwendungen /. Als Nächstes möchten Sie es zu Ihrem hinzufügen PFAD:

sudo ln -s /Applications/phantomjs-1.5.0/bin/phantomjs / usr / local / bin /

Ersetzen 1.5.0 mit Ihrer heruntergeladenen Version von PhantomJS. Bitte beachten Sie, dass nicht alle Systeme dies tun werden / usr / local / bin /. Einige Systeme haben: / usr / bin /, /Behälter/, oder usr / X11 / bin stattdessen.

Für Windows-Benutzer überprüfen Sie das kurze Tutorial hier. Sie wissen, dass Sie alles eingerichtet haben, wenn Sie Ihr Terminal öffnen und schreiben Phantomjs, und du bekommst keine fehler.

Wenn Sie sich unwohl fühlen, bearbeiten Sie Ihre PFAD, Notieren Sie sich, wo Sie PhantomJS entpackt haben, und ich zeige im nächsten Abschnitt eine andere Methode für die Einrichtung, obwohl ich Ihnen empfehle, Ihre PFAD.

PhantomJS-Knoten installieren

Das Einrichten des PhantomJS-Knotens ist wesentlich einfacher. Sofern Sie NodeJS installiert haben, können Sie die Installation über npm durchführen:

npm install phantom

Wenn Sie Ihre nicht bearbeitet haben PFAD Im vorherigen Schritt können Sie bei der Installation von PhantomJS in die Phantom/ Verzeichnis von npm heruntergezogen und diese Zeile in bearbeiten Phantom.js.

ps = child.spawn ('phantomjs', args.concat ([__ dirname + '/shim.js', port]));

Ändern Sie den Pfad zu:

ps = child.spawn ('/ pfad / nach / phantomjs-1.5.0 / bin / phantomjs', args.concat ([__ dirname + '/shim.js', port]));

Sobald dies erledigt ist, können Sie es testen, indem Sie diesen Code ausführen:

 var phantom = erfordern ('phantom'); phantom.create (Funktion (ph) return ph.createPage (Funktion (Seite) return page.open ("http://www.google.com", Funktion (Status) console.log ("geöffnetes Google?" , status); return page.evaluate ((function () return document.title;), function (Ergebnis) console.log ('Seitentitel ist' + Ergebnis); return ph.exit ();); );););

Wenn Sie dies in der Befehlszeile ausführen, sollte Folgendes angezeigt werden:

geöffnetes google? Erfolg Seitentitel ist Google

Wenn Sie das verstanden haben, sind Sie fertig und bereit zu gehen. Wenn nicht, schreibe einen Kommentar und ich werde versuchen, dir zu helfen!

PhantomJS-Knoten verwenden

Um Ihnen die Arbeit zu erleichtern, habe ich eine JS-Datei namens phantomServer.js Im Download, der einige APIs von PhantomJS verwendet, um eine Webseite zu laden. Es wartet 5 Sekunden, bevor es JavaScript ausführt, das die Seite kratzt. Sie können es ausführen, indem Sie zu dem Verzeichnis navigieren und den folgenden Befehl in Ihrem Terminal eingeben:

 Knoten phantomServer.js

Ich werde einen Überblick darüber geben, wie es hier funktioniert. Zunächst benötigen wir PhantomJS:

 var phantom = erfordern ('phantom');

Als Nächstes implementieren wir einige Methoden aus der API. Wir erstellen nämlich eine Seiteninstanz und rufen dann die öffnen() Methode:

 phantom.create (function (ph) return ph.createPage (function (page) // Ab hier können wir die API-Methoden von PhantomJS verwenden. return page.open ("http://tilomitra.com/repository/screenscrape") /ajax.html ", Funktion (Status) // Die Seite ist jetzt geöffnet. console.log (" Geöffnete Site? ", Status););););

Sobald die Seite geöffnet ist, können wir JavaScript in die Seite einfügen. Lass uns jQuery über die page.injectJs () Methode:

 phantom.create (Funktion (ph) return ph.createPage (Funktion (Seite) return page.open ("http://tilomitra.com/repository/screenscrape/ajax.html"), function (status) console.log ("geöffnete Site?", Status); page.injectJs ('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'), function () // jQuery Geladen // Wir können Dinge wie $ ("body") verwenden. Html () hier.););););

jQuery ist jetzt geladen, aber wir wissen nicht, ob der dynamische Inhalt der Seite noch geladen wurde. Um dies zu berücksichtigen, füge ich normalerweise meinen Scrap-Code in ein setTimeout () Funktion, die nach einem bestimmten Zeitintervall ausgeführt wird. Wenn Sie eine dynamischere Lösung wünschen, können Sie mit der PhantomJS-API bestimmte Ereignisse überwachen und emulieren. Lass uns mit dem einfachen Fall gehen:

 setTimeout (function () return page.evaluate (function () // Holen Sie sich mit jQuery die gewünschten Elemente von der Seite. // Eine gute Möglichkeit ist, ein Objekt mit allen benötigten jQuery-Befehlen zu füllen und das Objekt zurückzugeben . var h2Arr = [], // Array, das alle HTML-Elemente für H2-Elemente enthält pArr = []; // Array, das alle HTML-Elemente für P-Elemente enthält // Füllen Sie die beiden Arrays $ ('h2') aus. h2Arr.push ($ (this) .html ());); $ ('p'). each (function () pArr.push ($ (this) .html ());); // Rückgabe dieser Daten Rückgabe h2: h2Arr, p: pArr, function (Ergebnis) console.log (Ergebnis); // Abmelden der Daten. Ph.exit ();; 5000);

Alles zusammen, unser phantomServer.js Datei sieht so aus:

 var phantom = erfordern ('phantom'); phantom.create (Funktion (ph) return ph.createPage (Funktion (Seite) return page.open ("http://tilomitra.com/repository/screenscrape/ajax.html"), function (status) console.log ("geöffnete Site?", Status); page.injectJs ('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'), function () // jQuery Geladen . // Warten Sie etwas, bis AJAX-Inhalte auf der Seite geladen werden. Hier warten wir 5 Sekunden. SetTimeout (function () return page.evaluate (function () // Holen Sie sich mit jQuery, was Sie wollen Eine gute Möglichkeit ist, ein Objekt mit allen jQuery-Befehlen zu füllen, die Sie benötigen, und dann das Objekt zurückzugeben. Var h2Arr = [], pArr = []; $ ('h2'). Each (function () h2Arr.push ($ (this) .html ());); $ ('p'). each (function () pArr.push ($ (this) .html ());); return h2: h2Arr, p: pArr;, Funktion (Ergebnis) console.log (Ergebnis); ph.exit ();;, 5000);););););

Diese Implementierung ist ein wenig grob und unstrukturiert, macht aber den Punkt klar. Mit PhantomJS können wir eine Seite mit dynamischen Inhalten kratzen! Ihre Konsole sollte Folgendes ausgeben:

 → Knoten phantomServer.js geöffnete Site? erfolg h2: ['artikel 1', 'artikel 2', 'artikel 3'], p: ['Lorem ipsum dolor sitzen amet, consectetur adipiscing elit.' ',' Ut sed nulla turpis, in faucibus ante. Vivamus ut malesuada est. Curabitur vel enim purus pharetra tempor id in tellus. ',' Curabitur euismod hendrerit quam ut euismod. Ut leo sem, viverra nec gravida nec, tristique nec arcu. ' ]

Fazit

In diesem Lernprogramm haben wir zwei verschiedene Möglichkeiten zum Ausführen von Web Scraping beschrieben. Wenn Sie von einer statischen Webseite kratzen, können Sie YQL nutzen, das einfach einzurichten und zu verwenden ist. Andererseits können wir für dynamische Websites PhantomJS nutzen. Es ist etwas schwieriger einzurichten, bietet jedoch mehr Funktionen. Denken Sie daran: Sie können PhantomJS auch für statische Sites verwenden!

Wenn Sie Fragen zu diesem Thema haben, wenden Sie sich bitte an den untenstehenden Link. Ich werde mein Bestes tun, um Ihnen zu helfen.