Le guide ultime pour créer des grattoirs Web évolutifs avec Scrapy

Publié: 2022-03-10
Résumé rapide ↬ Scrapy est un framework Python open source populaire pour l'écriture de scrapers Web évolutifs. Dans ce didacticiel, nous vous expliquerons étape par étape comment utiliser Scrapy pour rassembler une liste de films primés aux Oscars sur Wikipedia.

Le scraping Web est un moyen de récupérer des données sur des sites Web sans avoir besoin d'accéder aux API ou à la base de données du site Web. Vous n'avez besoin que d'accéder aux données du site - tant que votre navigateur peut accéder aux données, vous pourrez les récupérer.

De manière réaliste, la plupart du temps, vous pouvez simplement parcourir un site Web manuellement et récupérer les données "à la main" en utilisant le copier-coller, mais dans de nombreux cas, cela vous prendrait de nombreuses heures de travail manuel, ce qui pourrait finir par vous coûter un beaucoup plus que les données ne valent, surtout si vous avez embauché quelqu'un pour faire la tâche à votre place. Pourquoi embaucher quelqu'un pour travailler 1 à 2 minutes par requête alors que vous pouvez faire en sorte qu'un programme exécute une requête automatiquement toutes les quelques secondes ?

Par exemple, disons que vous souhaitez compiler une liste des lauréats des Oscars pour la meilleure image, ainsi que leur réalisateur, les acteurs principaux, la date de sortie et la durée d'exécution. En utilisant Google, vous pouvez voir qu'il existe plusieurs sites qui répertorient ces films par nom, et peut-être quelques informations supplémentaires, mais en général, vous devrez suivre avec des liens pour capturer toutes les informations que vous souhaitez.

De toute évidence, il serait peu pratique et fastidieux de parcourir chaque lien de 1927 à aujourd'hui et d'essayer manuellement de trouver les informations sur chaque page. Avec le web scraping, il nous suffit de trouver un site Web avec des pages contenant toutes ces informations, puis d'orienter notre programme dans la bonne direction avec les bonnes instructions.

Dans ce didacticiel, nous utiliserons Wikipedia comme site Web car il contient toutes les informations dont nous avons besoin, puis nous utiliserons Scrapy sur Python comme outil pour récupérer nos informations.

Plus après saut! Continuez à lire ci-dessous ↓

Quelques mises en garde avant de commencer :

Le scraping de données implique d'augmenter la charge du serveur pour le site que vous scrapez, ce qui signifie un coût plus élevé pour les entreprises hébergeant le site et une expérience de qualité inférieure pour les autres utilisateurs de ce site. La qualité du serveur qui exécute le site Web, la quantité de données que vous essayez d'obtenir et la vitesse à laquelle vous envoyez des demandes au serveur modéreront l'effet que vous avez sur le serveur. Gardant cela à l'esprit, nous devons nous assurer que nous nous en tenons à quelques règles.

La plupart des sites ont également un fichier appelé robots.txt dans leur répertoire principal. Ce fichier établit des règles pour les répertoires auxquels les sites ne veulent pas que les scrapers accèdent. La page des conditions générales d'un site Web vous indiquera généralement quelle est sa politique en matière de récupération de données. Par exemple, la page des conditions d'IMDB contient la clause suivante :

Robots et grattage d'écran : Vous ne pouvez pas utiliser l'exploration de données, les robots, le grattage d'écran ou des outils similaires de collecte et d'extraction de données sur ce site, sauf avec notre consentement écrit exprès, comme indiqué ci-dessous.

Avant d'essayer d'obtenir les données d'un site Web, nous devons toujours consulter les conditions d'utilisation du site Web et le robots.txt pour nous assurer que nous obtenons des données légales. Lors de la construction de nos scrapers, nous devons également nous assurer que nous ne submergeons pas un serveur avec des requêtes qu'il ne peut pas gérer.

Heureusement, de nombreux sites Web reconnaissent la nécessité pour les utilisateurs d'obtenir des données et les rendent disponibles via des API. Si ceux-ci sont disponibles, il est généralement beaucoup plus facile d'obtenir des données via l'API que via le scraping.

Wikipedia autorise le scraping de données, tant que les bots ne vont pas "trop ​​vite", comme spécifié dans leur robots.txt . Ils fournissent également des ensembles de données téléchargeables afin que les utilisateurs puissent traiter les données sur leurs propres machines. Si nous allons trop vite, les serveurs bloqueront automatiquement notre adresse IP, nous mettrons donc en place des minuteries afin de respecter leurs règles.

Prise en main, installation des bibliothèques pertinentes à l'aide de Pip

Tout d'abord, pour commencer, installons Scrapy.

les fenêtres

Installez la dernière version de Python à partir de https://www.python.org/downloads/windows/

Remarque : les utilisateurs de Windows auront également besoin de Microsoft Visual C++ 14.0, que vous pouvez récupérer à partir de « Microsoft Visual C++ Build Tools » ici.

Vous voudrez également vous assurer que vous disposez de la dernière version de pip.

Dans cmd.exe , tapez :

 python -m pip install --upgrade pip pip install pypiwin32 pip install scrapy

Cela installera Scrapy et toutes les dépendances automatiquement.

Linux

Vous devez d'abord installer toutes les dépendances :

Dans Terminal, saisissez :

 sudo apt-get install python3 python3-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev

Une fois que tout est installé, tapez simplement :

 pip install --upgrade pip

Pour vous assurer que pip est mis à jour, puis :

 pip install scrapy

Et tout est fait.

Mac

Vous devez d'abord vous assurer d'avoir un compilateur C sur votre système. Dans Terminal, saisissez :

 xcode-select --install

Après cela, installez homebrew à partir de https://brew.sh/.

Mettez à jour votre variable PATH afin que les packages homebrew soient utilisés avant les packages système :

 echo "export PATH=/usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc source ~/.bashrc

Installez Python :

 brew install python

Et puis assurez-vous que tout est mis à jour :

 brew update; brew upgrade python

Après cela, installez simplement Scrapy en utilisant pip :

 pip install Scrapy
> ## Vue d'ensemble de Scrapy, comment les pièces s'emboîtent, analyseurs, araignées, etc.

Vous allez écrire un script appelé "Spider" pour que Scrapy s'exécute, mais ne vous inquiétez pas, les araignées Scrapy ne sont pas du tout effrayantes malgré leur nom. La seule similitude entre les araignées Scrapy et les vraies araignées est qu'elles aiment ramper sur le Web.

À l'intérieur de l'araignée se trouve une class que vous définissez et qui indique à Scrapy quoi faire. Par exemple, où commencer à explorer, les types de requêtes qu'il effectue, comment suivre les liens sur les pages et comment il analyse les données. Vous pouvez même ajouter des fonctions personnalisées pour traiter également les données, avant de les restituer dans un fichier.

## Écrivez votre première araignée, écrivez une araignée simple pour permettre un apprentissage pratique

Pour démarrer notre première araignée, nous devons d'abord créer un projet Scrapy. Pour ce faire, saisissez ceci dans votre ligne de commande :

 scrapy startproject oscars

Cela créera un dossier avec votre projet.

Nous allons commencer avec une araignée de base. Le code suivant doit être entré dans un script python. Ouvrez un nouveau script python dans /oscars/spiders et nommez-le oscars_spider.py

Nous allons importer Scrapy.

 import scrapy

Nous commençons ensuite à définir notre classe Spider. Tout d'abord, nous définissons le nom, puis les domaines que l'araignée est autorisée à gratter. Enfin, nous disons à l'araignée d'où commencer à gratter.

 class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ['https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture']

Ensuite, nous avons besoin d'une fonction qui capture les informations que nous voulons. Pour l'instant, nous allons juste saisir le titre de la page. Nous utilisons CSS pour trouver la balise qui porte le texte du titre, puis nous l'extrayons. Enfin, nous renvoyons les informations à Scrapy pour qu'elles soient enregistrées ou écrites dans un fichier.

 def parse(self, response): data = {} data['title'] = response.css('title::text').extract() yield data

Enregistrez maintenant le code dans /oscars/spiders/oscars_spider.py

Pour exécuter cette araignée, allez simplement sur votre ligne de commande et tapez :

 scrapy crawl oscars

Vous devriez voir une sortie comme celle-ci :

 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished) 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished) 2019-05-02 14:39:31 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: oscars) ... 2019-05-02 14:39:32 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.engine] DEBUG: Crawled (200) (referer: None) 2019-05-02 14:39:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture> {'title': ['Academy Award for Best Picture - Wikipedia']} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Closing spider (finished) 2019-05-02 14:39:34 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 589, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 74517, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 5, 2, 7, 39, 34, 264319), 'item_scraped_count': 1, 'log_count/DEBUG': 3, 'log_count/INFO': 9, 'response_received_count': 2, 'robotstxt/request_count': 1, 'robotstxt/response_count': 1, 'robotstxt/response_status_count/200': 1, 'scheduler/dequeued': 1, 'scheduler/dequeued/memory': 1, 'scheduler/enqueued': 1, 'scheduler/enqueued/memory': 1, 'start_time': datetime.datetime(2019, 5, 2, 7, 39, 31, 431535)} 2019-05-02 14:39:34 [scrapy.core.engine] INFO: Spider closed (finished)

Félicitations, vous avez construit votre premier grattoir Scrapy de base !

Code complet :

 import scrapy class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"] def parse(self, response): data = {} data['title'] = response.css('title::text').extract() yield data

Évidemment, nous voulons qu'il en fasse un peu plus, alors voyons comment utiliser Scrapy pour analyser les données.

Tout d'abord, familiarisons-nous avec le shell Scrapy. Le shell Scrapy peut vous aider à tester votre code pour vous assurer que Scrapy récupère les données souhaitées.

Pour accéder au shell, saisissez ceci dans votre ligne de commande :

 scrapy shell “https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture”

Cela ouvrira essentiellement la page vers laquelle vous l'avez dirigé et vous permettra d'exécuter des lignes de code simples. Par exemple, vous pouvez afficher le code HTML brut de la page en saisissant :

 print(response.text)

Ou ouvrez la page dans votre navigateur par défaut en saisissant :

 view(response)

Notre objectif ici est de trouver le code qui contient les informations que nous voulons. Pour l'instant, essayons de saisir uniquement les noms des titres de films.

Le moyen le plus simple de trouver le code dont nous avons besoin est d'ouvrir la page dans notre navigateur et d'inspecter le code. Dans cet exemple, j'utilise Chrome DevTools. Faites simplement un clic droit sur n'importe quel titre de film et sélectionnez "inspecter":

Utilisation de Chrome DevTools pour inspecter HTML et CSS
Fenêtre des outils de développement Chrome. ( Grand aperçu )

Comme vous pouvez le voir, les gagnants des Oscars ont un fond jaune tandis que les nominés ont un fond uni. Il y a aussi un lien vers l'article sur le titre du film, et les liens pour les films se terminent par film) . Maintenant que nous savons cela, nous pouvons utiliser un sélecteur CSS pour récupérer les données. Dans le shell Scrapy, tapez :

 response.css(r"tr[] a[href*='film)']").extract()

Comme vous pouvez le voir, vous avez maintenant une liste de tous les gagnants des Oscars du meilleur film !

 > response.css(r"tr[] a[href*='film']").extract() ['<a href="/wiki/Wings_(1927_film)" title="Wings (1927 film)">Wings</a>', ... '<a href="/wiki/Green_Book_(film)" title="Green Book (film)">Green Book</a>', '<a href="/wiki/Jim_Burke_(film_producer)" title="Jim Burke (film producer)">Jim Burke</a>']

Pour en revenir à notre objectif principal, nous voulons une liste des lauréats des Oscars pour la meilleure image, ainsi que leur réalisateur, les acteurs principaux, la date de sortie et la durée d'exécution. Pour ce faire, nous avons besoin de Scrapy pour récupérer les données de chacune de ces pages de film.

Nous devrons réécrire quelques éléments et ajouter une nouvelle fonction, mais ne vous inquiétez pas, c'est assez simple.

Nous allons commencer par amorcer le grattoir de la même manière que précédemment.

 import scrapy, time class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"]

Mais cette fois, deux choses vont changer. Tout d'abord, nous importerons le time avec scrapy car nous voulons créer une minuterie pour limiter la vitesse à laquelle le bot scrape. De plus, lorsque nous analysons les pages pour la première fois, nous voulons uniquement obtenir une liste des liens vers chaque titre, afin que nous puissions à la place récupérer des informations sur ces pages.

 def parse(self, response): for href in response.css(r"tr[] a[href*='film)']::attr(href)").extract(): url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) time.sleep(5) yield req

Ici, nous faisons une boucle pour rechercher chaque lien sur la page qui se termine par film) avec le fond jaune, puis nous joignons ces liens ensemble dans une liste d'URL, que nous enverrons à la fonction parse_titles pour aller plus loin. Nous glissons également une minuterie pour qu'il ne demande des pages que toutes les 5 secondes. N'oubliez pas que nous pouvons utiliser le shell Scrapy pour tester nos champs response.css afin de nous assurer que nous obtenons les bonnes données !

 def parse_titles(self, response): for sel in response.css('html').extract(): data = {} data['title'] = response.css(r"h1[id='firstHeading'] i::text").extract() data['director'] = response.css(r"tr:contains('Directed by') a[href*='/wiki/']::text").extract() data['starring'] = response.css(r"tr:contains('Starring') a[href*='/wiki/']::text").extract() data['releasedate'] = response.css(r"tr:contains('Release date') li::text").extract() data['runtime'] = response.css(r"tr:contains('Running time') td::text").extract() yield data

Le vrai travail est fait dans notre fonction parse_data , où nous créons un dictionnaire appelé data , puis remplissons chaque clé avec les informations que nous voulons. Encore une fois, tous ces sélecteurs ont été trouvés à l'aide de Chrome DevTools comme démontré précédemment, puis testés avec le shell Scrapy.

La dernière ligne renvoie le dictionnaire de données à Scrapy pour le stocker.

Code complet :

 import scrapy, time class OscarsSpider(scrapy.Spider): name = "oscars" allowed_domains = ["en.wikipedia.org"] start_urls = ["https://en.wikipedia.org/wiki/Academy_Award_for_Best_Picture"] def parse(self, response): for href in response.css(r"tr[] a[href*='film)']::attr(href)").extract(): url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) time.sleep(5) yield req def parse_titles(self, response): for sel in response.css('html').extract(): data = {} data['title'] = response.css(r"h1[id='firstHeading'] i::text").extract() data['director'] = response.css(r"tr:contains('Directed by') a[href*='/wiki/']::text").extract() data['starring'] = response.css(r"tr:contains('Starring') a[href*='/wiki/']::text").extract() data['releasedate'] = response.css(r"tr:contains('Release date') li::text").extract() data['runtime'] = response.css(r"tr:contains('Running time') td::text").extract() yield data

Parfois, nous voudrons utiliser des proxies car les sites Web essaieront de bloquer nos tentatives de grattage.

Pour ce faire, nous n'avons qu'à changer quelques éléments. En utilisant notre exemple, dans notre def parse() , nous devons le remplacer par ce qui suit :

 def parse(self, response): for href in (r"tr[] a[href*='film)']::attr(href)").extract() : url = response.urljoin(href) print(url) req = scrapy.Request(url, callback=self.parse_titles) req.meta['proxy'] = "https://yourproxy.com:80" yield req

Cela acheminera les demandes via votre serveur proxy.

Déploiement et journalisation, montrent comment gérer réellement une araignée en production

Il est maintenant temps d'exécuter notre araignée. Pour que Scrapy commence à gratter puis à générer un fichier CSV, saisissez ce qui suit dans votre invite de commande :

 scrapy crawl oscars -o oscars.csv

Vous verrez une grande sortie, et après quelques minutes, elle se terminera et vous aurez un fichier CSV dans votre dossier de projet.

Compilation des résultats, montrez comment utiliser les résultats compilés dans les étapes précédentes

Lorsque vous ouvrez le fichier CSV, vous verrez toutes les informations que nous voulions (triées par colonnes avec des en-têtes). C'est vraiment aussi simple que cela.

Un CSV des films primés aux Oscars et des informations associées
Liste et informations sur les films primés aux Oscars. ( Grand aperçu )

Avec le data scraping, nous pouvons obtenir presque tous les ensembles de données personnalisés que nous voulons, tant que les informations sont accessibles au public. Ce que vous voulez faire de ces données dépend de vous. Cette compétence est extrêmement utile pour faire des études de marché, tenir à jour les informations sur un site Web et bien d'autres choses.

Il est assez facile de configurer votre propre grattoir Web pour obtenir vous-même des ensembles de données personnalisés, mais n'oubliez pas qu'il peut exister d'autres moyens d'obtenir les données dont vous avez besoin. Les entreprises investissent beaucoup pour fournir les données que vous souhaitez, il est donc juste que nous respections leurs termes et conditions.

Ressources supplémentaires pour en savoir plus sur Scrapy et Web Scraping en général

  • Le site officiel de Scrapy
  • Page GitHub de Scrapy
  • "Les 10 meilleurs outils de grattage de données et outils de grattage Web", API Scraper
  • "5 conseils pour le scraping Web sans être bloqué ou mis sur liste noire", API Scraper
  • Parsel, une bibliothèque Python pour utiliser des expressions régulières pour extraire des données de HTML.