Raclage d'écran avec Node.js

Vous avez peut-être utilisé NodeJS en tant que serveur Web, mais saviez-vous que vous pouvez également l'utiliser pour le nettoyage Web? Dans ce tutoriel, nous verrons comment supprimer des pages Web statiques - et des pages gênantes au contenu dynamique - à l'aide de NodeJS et de quelques modules utiles de NPM..



Un peu à propos du Web Scraping

Le scraping Web a toujours eu une connotation négative dans le monde du développement web - et pour cause. Dans le développement moderne, les API sont présentes pour les services les plus populaires et devraient être utilisées pour récupérer des données plutôt que de les extraire. Le problème inhérent au grattage est qu’il repose sur la structure visuelle de la page à gratter. Chaque fois que HTML change - si minime soit-il - il peut complètement casser votre code.

En dépit de ces défauts, il est important d’en apprendre un peu plus sur le raclage Web et sur certains des outils disponibles pour vous aider dans cette tâche. Lorsqu'un site ne révèle pas d'API ou de flux de syndication (RSS / Atom, etc.), la seule option qui nous reste pour obtenir ce contenu… est le grattage..

Remarque: Si vous ne pouvez pas obtenir les informations dont vous avez besoin par le biais d'une API ou d'un flux, cela signifie que le propriétaire ne veut pas que ces informations soient accessibles. Cependant, il y a des exceptions.


Pourquoi utiliser NodeJS?

Les grattoirs peuvent être écrits dans n’importe quelle langue. La raison pour laquelle j'aime utiliser Node tient à sa nature asynchrone, ce qui signifie que mon code n'est bloqué à aucun moment du processus. Je connais assez bien JavaScript, donc c'est un bonus supplémentaire. Enfin, il existe de nouveaux modules écrits pour NodeJS qui facilitent la suppression de sites Web de manière fiable (enfin, aussi fiable que puisse être le processus de récupération)! Commençons!


Raclage simple avec YQL

Commençons par le cas d'utilisation simple: les pages Web statiques. Il s’agit de vos pages Web standard. Pour ceux-ci, Yahoo! Le langage de requête (YQL) devrait très bien faire le travail. Pour ceux qui ne connaissent pas YQL, c'est une syntaxe de type SQL qui peut être utilisée pour travailler avec différentes API de manière cohérente..

YQL propose d'excellents tableaux pour aider les développeurs à obtenir du HTML sur une page. Ceux que je veux mettre en évidence sont:

  • html
  • data.html.cssselect
  • htmlstring

Passons en revue chacune d'elles et voyons comment les implémenter dans NodeJS..

html table

le html table est le moyen le plus simple de supprimer du HTML à partir d’une URL. Une requête régulière utilisant cette table ressemble à ceci:

Sélectionnez * à partir de HTML où url = "http://finance.yahoo.com/q?s=yhoo" et xpath = "// div [@ id =" yfi_headlines "] / div [2] / ul / li / a "

Cette requête est composée de deux paramètres: "url" et "xpath". L'URL est explicite. XPath consiste en une chaîne XPath indiquant à YQL quelle section du code HTML doit être renvoyée. Essayez cette requête ici.

Les paramètres supplémentaires que vous pouvez utiliser incluent navigateur (booléen), jeu de caractères (chaîne), et compat (chaîne). Je n'ai pas eu à utiliser ces paramètres, mais référez-vous à la documentation si vous avez des besoins spécifiques.

Pas à l'aise avec XPath?

Malheureusement, XPath n’est pas un moyen très répandu de parcourir l’arborescence HTML. Il peut être compliqué à lire et à écrire pour les débutants.

Regardons le tableau suivant, qui fait la même chose mais vous permet d'utiliser CSS à la place

data.html.cssselect table

le data.html.cssselect table est ma méthode préférée pour extraire du HTML d'une page. Cela fonctionne de la même manière que le html table mais vous permet de CSS au lieu de XPath. En pratique, cette table convertit le CSS en XPath sous le capot, puis appelle le html table, donc c'est un peu plus lent. La différence doit être négligeable pour les besoins de raclage.

Une requête régulière utilisant cette table ressemble à:

sélectionnez * depuis data.html.cssselect où url = "www.yahoo.com" et css = "# news a"

Comme vous pouvez le constater, il est beaucoup plus propre. Je vous recommande d'essayer cette méthode d'abord lorsque vous essayez de supprimer HTML à l'aide de YQL. Essayez cette requête ici.

htmlstring table

le htmlstring Le tableau est utile dans les cas où vous essayez d'extraire une grande partie du texte mis en forme d'une page Web..

L'utilisation de cette table vous permet d'extraire l'intégralité du contenu HTML de cette page dans une seule chaîne, plutôt que sous la forme d'un fichier JSON divisé en fonction de la structure DOM..

Par exemple, une réponse JSON normale qui gratte une Le tag ressemble à ceci:

"résultats": "a": "href": "…", "cible": "_blank", "contenu": "Le chef de la direction d'Apple cuisinier doit gravir les échelons"

Voyez comment les attributs sont définis en tant que propriétés? Au lieu de cela, la réponse du htmlstring la table ressemblerait à ceci:

"résultats": "résultat": "Le chef de la direction d’Apple doit gravir les échelons

Alors, pourquoi utiliseriez-vous cela? D'après mon expérience, cela s'avère très utile lorsque vous essayez de gratter une grande quantité de texte mis en forme. Par exemple, considérons l'extrait suivant:

Lorem ipsum dolor sit amet, consectetur elipiscing elit.

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

En utilisant le htmlstring tableau, vous pouvez obtenir ce code HTML sous forme de chaîne et utiliser regex pour supprimer les balises HTML, ce qui vous laisse uniquement le texte. Cette tâche est plus facile que d'effectuer une itération via JSON divisé en propriétés et objets enfants en fonction de la structure DOM de la page..


Utiliser YQL avec NodeJS

Maintenant que nous en savons un peu sur certaines des tables disponibles dans YQL, implémentons un scraper Web utilisant YQL et NodeJS. Heureusement, c’est très simple, grâce au node-yql module de Derek Gathright.

Nous pouvons installer le module en utilisant npm:

npm installer yql

Le module est extrêmement simple et consiste en une seule méthode: la YQL.exec () méthode. Il est défini comme suit:

fonction exec (requête de chaîne [, fonction de rappel] [, objet params] [, objet httpOptions])

Nous pouvons l'utiliser en l'exigeant et en appelant YQL.exec (). Par exemple, supposons que nous voulions effacer les titres de tous les articles de la page principale de Nettuts:

var YQL = require ("yql"); new YQL.exec ('select * from data.html.cssselect où url = "http://net.tutsplus.com/" et css = ". post_title a"', function (réponse) // réponse est composée de JSON que vous pouvez analyser);

La grande chose à propos de YQL est sa capacité à tester vos requêtes et à déterminer quel JSON vous récupérez en temps réel. Allez sur la console pour essayer cette requête ou cliquez ici pour voir le JSON brut.

le params et httpOptions les objets sont optionnels. Les paramètres peuvent contenir des propriétés telles que env (que vous utilisiez un environnement spécifique pour les tables) et format (XML ou JSON). Toutes les propriétés passées dans params sont encodés en URI et ajoutés à la chaîne de requête. le httpOptions objet est passé dans l'en-tête de la requête. Ici, vous pouvez spécifier si vous voulez activer SSL, par exemple.

Le fichier JavaScript, nommé yqlServer.js, contient le code minimal requis pour utiliser YQL. Vous pouvez l'exécuter en émettant la commande suivante dans votre terminal:

noeud yqlServer.js

Exceptions et autres outils notables

YQL est mon choix préféré pour supprimer le contenu des pages Web statiques, car il est facile à lire et à utiliser. Cependant, YQL échouera si la page Web en question a une robots.txt fichier qui refuse une réponse. Dans ce cas, vous pouvez consulter certains des utilitaires mentionnés ci-dessous ou utiliser PhantomJS, que nous aborderons dans la section suivante..

Node.io est un utilitaire de nœud utile spécialement conçu pour le raclage des données. Vous pouvez créer des travaux qui prennent des entrées, les traiter et renvoyer une sortie. Node.io est bien regardé sur Github et propose quelques exemples utiles pour vous aider à démarrer..

JSDOM est un projet très populaire qui implémente le DOM W3C en JavaScript. Lorsqu'il est fourni en HTML, il peut construire un DOM avec lequel vous pouvez interagir. Consultez la documentation pour voir comment vous pouvez utiliser ensemble JSDOM et toutes les bibliothèques JS (telles que jQuery) pour extraire des données de pages Web..


Raclage de pages avec contenu dynamique

Jusqu'à présent, nous avons examiné certains outils pouvant nous aider à gratter des pages Web avec du contenu statique. Avec YQL, c'est relativement facile. Malheureusement, on nous présente souvent des pages dont le contenu est chargé dynamiquement avec JavaScript. Dans ces cas, la page est souvent vide au début, puis le contenu est ajouté par la suite. Comment pouvons-nous traiter ce problème?

Un exemple

Laissez-moi vous donner un exemple de ce que je veux dire. J'ai téléchargé un simple fichier HTML sur mon propre site Web, qui ajoute du contenu, via JavaScript, deux secondes après le document.ready () la fonction est appelée. Vous pouvez consulter la page ici. Voici à quoi ressemble la source:

   Page de test avec du contenu ajouté après le chargement de la page   Le contenu de cette page est ajouté au DOM une fois la page chargée.. 

Maintenant, essayons de gratter le texte à l'intérieur du

en utilisant YQL.

var YQL = require ("yql"); new YQL.exec ('select * from data.html.cssselect où url = "http://tilomitra.com/repository/screenscrape/ajax.html" et css = "# content"', fonction (réponse) // Cela retournera undefined! La récupération a échoué! Console.log (response.results););

Vous remarquerez que YQL revient indéfini parce que, lorsque la page est chargée, le

est vide. Le contenu n'a pas encore été ajouté. Vous pouvez essayer la requête par vous-même ici.

Regardons comment nous pouvons contourner ce problème!

Entrez PhantomJS

PhantomJS peut charger des pages Web et imiter un navigateur Webkit sans interface graphique.

Ma méthode préférée pour extraire les informations de ces sites consiste à utiliser PhantomJS. PhantomJS se décrit comme un "Webkit sans tête avec une API JavaScript. En termes simples, cela signifie que PhantomJS peut charger des pages Web et imiter un navigateur Webkit sans interface graphique. En tant que développeur, nous pouvons faire appel à des méthodes spécifiques fournies par PhantomJS exécuter du code sur la page. Comme il se comporte comme un navigateur, les scripts de la page Web sont exécutés comme dans un navigateur classique..

Pour obtenir des données de notre page, nous allons utiliser PhantomJS-Node, un super petit projet open-source qui relie PhantomJS à NodeJS. Sous le capot, ce module exécute PhantomJS en tant que processus enfant..

Installer PhantomJS

Avant de pouvoir installer le module PhantomJS-Node NPM, vous devez installer PhantomJS. L’installation et la construction de PhantomJS peuvent être un peu difficiles, cependant.

Tout d’abord, rendez-vous sur PhantomJS.org et téléchargez la version correspondant à votre système d’exploitation. Dans mon cas, c'était Mac OSX.

Après le téléchargement, décompressez-le à un endroit tel que /Applications/. Ensuite, vous voulez l'ajouter à votre CHEMIN:

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

Remplacer 1.5.0 avec votre version téléchargée de PhantomJS. Sachez que tous les systèmes n’auront pas / usr / local / bin /. Certains systèmes auront: / usr / bin /, /poubelle/, ou usr / X11 / bin au lieu.

Pour les utilisateurs de Windows, consultez le court tutoriel ici. Vous saurez que vous êtes tous configurés lorsque vous ouvrez votre terminal et écrivez Phantomjs, et vous n'obtenez aucune erreur.

Si vous ne souhaitez pas éditer votre CHEMIN, Prenez note de l'endroit où vous avez décompressé PhantomJS et je montrerai une autre façon de le configurer dans la section suivante, bien que je vous recommande de modifier votre CHEMIN.

Installation de PhantomJS-Node

Configurer PhantomJS-Node est beaucoup plus facile. Si vous avez installé NodeJS, vous pouvez l’installer via npm:

npm installer fantôme

Si vous n'avez pas édité votre CHEMIN à l'étape précédente, lors de l'installation de PhantomJS, vous pouvez accéder au fantôme/ répertoire tiré par npm et éditez cette ligne phantom.js.

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

Changer le chemin en:

ps = child.spawn ('/ chemin / vers / phantomjs-1.5.0 / bin / phantomjs', args.concat ([__ nomrépertoire + '/shim.js', port]));

Une fois que cela est fait, vous pouvez le tester en exécutant ce code:

 var phantom = require ('phantom'); phantom.create (function (ph) return ph.createPage (function (page) return page.open ("http://www.google.com"), function (status) console.log ("google ouvert?" , status); return page.evaluate ((function () return document.title;), function (result) console.log ('Le titre de la page est' + result); return ph.exit ();); );););

Exécuter ceci sur la ligne de commande devrait afficher les éléments suivants:

ouvert google? succès Le titre de la page est Google

Si vous avez cela, vous êtes prêt et prêt à partir. Si non, postez un commentaire et je vais essayer de vous aider!

Utiliser PhantomJS-Node

Pour vous faciliter la tâche, j’ai inclus un fichier JS, appelé phantomServer.js dans le téléchargement qui utilise certaines API de PhantomJS pour charger une page Web. Il attend 5 secondes avant d'exécuter du JavaScript qui gratte la page. Vous pouvez l'exécuter en allant dans le répertoire et en émettant la commande suivante dans votre terminal:

 noeud phantomServer.js

Je vais donner un aperçu de la façon dont cela fonctionne ici. Premièrement, nous avons besoin de PhantomJS:

 var phantom = require ('phantom');

Ensuite, nous implémentons certaines méthodes de l'API. À savoir, nous créons une instance de page, puis appelons le ouvrir() méthode:

 phantom.create (function (ph) return ph.createPage (function (page) // A partir de maintenant, nous pouvons utiliser les méthodes de l'API de PhantomJS. return page.open ("http://tilomitra.com/repository/screenscrape /ajax.html ", fonction (statut) // La page est maintenant ouverte console.log (" site ouvert? ", statut););););

Une fois la page ouverte, nous pouvons injecter du JavaScript dans la page. Injectons jQuery via le page.injectJs () méthode:

 phantom.create (function (ph) return ph.createPage (function (page) return page.open ("http://tilomitra.com/repository/screenscrape/ajax.html", fonction (statut) console.log ("site ouvert?", statut); page.injectJs ('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', function () // jQuery Loaded // Nous pouvons utiliser des choses comme $ ("body"). Html () ici););););

jQuery est maintenant chargé, mais nous ne savons pas encore si le contenu dynamique de la page a été chargé. Pour en tenir compte, je mets généralement mon code de grattage dans un setTimeout () fonction qui s'exécute après un certain intervalle de temps. Si vous souhaitez une solution plus dynamique, l’API PhantomJS vous permet d’écouter et d’émuler certains événements. Allons avec le cas simple:

 setTimeout (function () return page.evaluate (function () // Obtenez ce que vous voulez de la page en utilisant jQuery. // Un bon moyen est de renseigner un objet avec toutes les commandes jQuery dont vous avez besoin, puis de renvoyer l'objet. . var h2Arr = [], // tableau qui contient tout le html pour les éléments h2 pArr = []; // tableau qui contient tout le html pour les éléments p // Remplit les deux tableaux $ ('h2'). each (function () h2Arr.push ($ (this) .html ());); $ ('p'). each (function () pArr.push ($ (this) .html ()); // Renvoyer ces données return h2: h2Arr, p: pArr, function (result) console.log (result); // Déconnectez les données. Ph.exit ();) 5000);

Mettre tout cela ensemble, notre phantomServer.js Le fichier ressemble à ceci:

 var phantom = require ('phantom'); phantom.create (function (ph) return ph.createPage (function (page) return page.open ("http://tilomitra.com/repository/screenscrape/ajax.html", fonction (statut) console.log ("site ouvert?", statut); page.injectJs ('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', function () // jQuery Loaded . // Attend un peu que le contenu AJAX soit chargé sur la page, ici nous attendons 5 secondes. SetTimeout (function () return page.evaluate (function () // Obtenez ce que vous voulez de la page en utilisant jQuery Une bonne méthode consiste à renseigner un objet avec toutes les commandes jQuery dont vous avez besoin, puis à le renvoyer. Var h2Arr = [], pArr = []; $ ('h2'). Each (function () h2Arr.push ($ (this) .html ());); $ ('p'). each (function () pArr.push ($ (this) .html ());); return h2: h2Arr, p: pArr;, fonction (résultat) console.log (résultat); ph.exit (););, 5000);););););););

Cette implémentation est un peu rudimentaire et désorganisée, mais elle en fait ressortir le sens. En utilisant PhantomJS, nous sommes en mesure de gratter une page qui a un contenu dynamique! Votre console devrait afficher les éléments suivants:

 → noeud phantomServer.js a ouvert le site? success h2: ['Article 1', 'Article 2', 'Article 3'], p: ['Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'Ut sed nulla turpis, in faucibus ante. Vivamus ut malesuada est. Curabitur vel enim eget purus pharetra tempor id in tellus. ',' Curabitur euismod hendrerit quam ut euismod. Ut leo sem, viverra nca gravida nec, tristique nec arcu. ' ]

Conclusion

Dans ce didacticiel, nous avons examiné deux méthodes différentes pour effectuer un scraping Web. Si vous extrayez une page Web statique, nous pouvons tirer parti de YQL, qui est facile à configurer et à utiliser. D'autre part, pour les sites dynamiques, nous pouvons tirer parti de PhantomJS. C'est un peu plus difficile à configurer, mais offre plus de fonctionnalités. Rappelez-vous: vous pouvez aussi utiliser PhantomJS pour les sites statiques!

Si vous avez des questions sur ce sujet, n'hésitez pas à demander ci-dessous et je ferai de mon mieux pour vous aider.