Scrapage Web côté client avec JavaScript à l'aide de jQuery et Regex

Lorsque je construisais mon premier projet open-source, codeBadges, je pensais qu'il serait facile d'obtenir des données de profil utilisateur à partir de tous les principaux sites Web d'apprentissage de code.

J'étais familier avec les appels API et recevais des demandes. J'ai pensé que je pourrais simplement utiliser jQuery pour récupérer les données des différentes API et les utiliser.

var name = 'codemzy'; $.get('//api.github.com/users/' + name, function(response) { var followers = response.followers;});

Eh bien, c'était facile. Mais il s'avère que tous les sites Web ne disposent pas d'une API publique à partir de laquelle vous pouvez simplement récupérer les données souhaitées.

Mais ce n'est pas parce qu'il n'y a pas d'API publique que vous devez abandonner! Vous pouvez utiliser le web scraping pour récupérer les données, avec seulement un peu de travail supplémentaire .

Voyons comment nous pouvons utiliser le web scraping côté client avec JavaScript.

Pour un exemple, je vais récupérer mes informations d'utilisateur à partir de mon profil public freeCodeCamp. Mais vous pouvez utiliser ces étapes sur n'importe quelle page HTML publique.

La première étape de la récupération des données consiste à récupérer le code HTML de la page entière à l'aide d'une .getrequête jQuery .

var name = "codemzy";$.get('//www.freecodecamp.com/' + name, function(response) { console.log(response);});

Génial, le code source de la page entière vient d'être connecté à la console.

Remarque: si vous obtenez une erreur à ce stade du type No ‘Access-Control-Allow-Origin’ header is present on the requested resourcene vous inquiétez pas. Faites défiler jusqu'à la section Ne laissez pas CORS vous arrêter de cet article.

C'était facile. En utilisant JavaScript et jQuery, le code ci-dessus demande une page à www.freecodecamp.org, comme le ferait un navigateur. Et freeCodeCamp répond avec la page. Au lieu d'un navigateur exécutant le code pour afficher la page, nous obtenons le code HTML.

Et c'est ce qu'est le scraping Web, extraire des données de sites Web.

Ok, la réponse n'est pas aussi nette que les données que nous récupérons d'une API.

Mais… nous avons les données, quelque part là-dedans.

Une fois que nous avons le code source, les informations dont nous avons besoin sont là, nous devons simplement récupérer les données dont nous avons besoin!

Nous pouvons rechercher dans la réponse pour trouver les éléments dont nous avons besoin.

Disons que nous voulons savoir combien de défis l'utilisateur a complétés, à partir de la réponse du profil utilisateur que nous avons reçue.

Au moment de la rédaction de cet article, les défis complétés par un campeur sont organisés en tableaux sur le profil de l'utilisateur. Donc, pour obtenir le nombre total de défis terminés, nous pouvons compter le nombre de lignes.

Une façon consiste à envelopper la réponse entière dans un objet jQuery, afin que nous puissions utiliser des méthodes jQuery comme .find()pour obtenir les données.

// number of challenges completedvar challenges = $(response).find('tbody tr').length;

Cela fonctionne bien - nous obtenons le bon résultat. Mais ce n'est pas un bon moyen d'obtenir le résultat que nous recherchons. Transformer la réponse en objet jQuery charge en fait toute la page, y compris tous les scripts externes, polices et feuilles de style de cette page… Oh oh!

Nous avons besoin de quelques bits de données. Nous n'avons vraiment pas besoin de la page pour charger, et certainement pas de toutes les ressources externes qui l'accompagnent.

Nous pourrions supprimer les balises de script, puis exécuter le reste de la réponse via jQuery. Pour ce faire, nous pourrions utiliser Regex pour rechercher des modèles de script dans le texte et les supprimer.

Ou mieux encore, pourquoi ne pas utiliser Regex pour trouver ce que nous recherchons en premier lieu?

// number of challenges completedvar challenges = response.replace(/[\s|\S]*?/g).match(//g).length;

Et il fonctionne! En utilisant le code Regex ci-dessus, nous supprimons les lignes d'en-tête du tableau (qui ne contenaient aucun défi), puis nous faisons correspondre toutes les lignes du tableau pour compter le nombre de défis terminés.

C'est encore plus facile si les données que vous voulez sont juste là dans la réponse en texte brut. Au moment de la rédaction de cet article, les points utilisateur étaient au format HTML comme

[ 1498 ]

en attente d'être gratté.

var points = response.match(/

\[ ([\d]*?) \]/)[1];

Dans le modèle Regex ci-dessus, nous faisons correspondre l'élément h1 que nous recherchons, y compris celui [ ]qui entoure les points, et regroupons tout nombre à l'intérieur avec ([\d]*?).Nous récupérons un tableau, le premier [0]élément est la correspondance entière et le second [1]est notre correspondance de groupe (nos points ).

Regex est utile pour faire correspondre toutes sortes de modèles dans des chaînes, et il est idéal pour rechercher dans notre réponse pour obtenir les données dont nous avons besoin.

You can use the same 3 step process to scrape profile data from a variety of websites:

  1. Use client-side JavaScript
  2. Use jQuery to scrape the data
  3. Use Regex to filter the data for the relevant information

Until I hit a problem, CORS.

Don’t Let CORS Stop You!

CORS or Cross-Origin Resource Sharing, can be a real problem with client-side web scraping.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. And because we are using client-side Javascript on the front end for web scraping, CORS errors can occur.

Here’s an example trying to scrape profile data from CodeWars…

var name = "codemzy";$.get('//www.codewars.com/users/' + name, function(response) { console.log(response);});

At the time of writing, running the above code gives you a CORS related error.

If there is noAccess-Control-Allow-Origin header from the place you’re scraping, you can run into problems.

The bad news is, you need to run these sorts of requests server-side to get around this issue.

Whaaaaaaaat, this is supposed to be client-side web scraping?!

The good news is, thanks to lots of other wonderful developers that have run into the same issues, you don’t have to touch the back end yourself.

Staying firmly within our front end script, we can use cross-domain tools such as Any Origin, Whatever Origin, All Origins, crossorigin and probably a lot more. I have found that you often need to test a few of these to find the one that will work on the site you are trying to scrape.

Back to our CodeWars example, we can send our request via a cross-domain tool to bypass the CORS issue.

var name = "codemzy";var url = "//anyorigin.com/go?url=" + encodeURIComponent("//www.codewars.com/users/") + name + "&callback=?";$.get(url, function(response) { console.log(response);});

And just like magic, we have our response.