Web Scraping avec Scrapy : La méthode facile
Mihai Maxim le 30 janvier 2023

Le scraping web avec Scrapy
Scrapy est une puissante bibliothèque Python permettant d'extraire des données de sites web. Elle est rapide, efficace et facile à utiliser - croyez-moi, je suis passé par là. Que vous soyez un data scientist, un développeur ou quelqu'un qui aime jouer avec les données, Scrapy a quelque chose à vous offrir. Et le mieux, c'est qu'il est gratuit et open-source.
Les projets Scrapy sont livrés avec une structure de fichiers qui vous aide à organiser votre code et vos données. Cela facilite la construction et la maintenance des scrappeurs web, et vaut donc la peine d'être envisagé si vous envisagez de faire du web scraping de manière sérieuse. Le web scraping avec Scrapy C'est comme si vous aviez un assistant utile (bien que virtuel) à vos côtés lorsque vous vous embarquez dans votre voyage d'extraction de données.
Ce que nous allons construire
Lorsque vous apprenez une nouvelle technique, c'est une chose de lire sur le sujet et une autre de le faire. C'est pourquoi nous avons décidé de construire ensemble un scraper tout au long de ce guide. C'est la meilleure façon d'acquérir une compréhension pratique du fonctionnement du web scraping avec Scrapy.
Qu'allons-nous construire exactement ? Nous allons construire un scraper qui récupère les définitions de mots du site Web Urban Dictionary. Il s'agit d'une cible amusante qui rendra le processus d'apprentissage plus agréable. Notre scraper sera simple - il renverra les définitions de divers mots trouvés sur le site Web Urban Dictionary. Nous utiliserons le support intégré de Scrapy pour sélectionner et extraire des données de documents HTML afin d'en extraire les définitions dont nous avons besoin.
Commençons donc ! Dans la prochaine section, nous passerons en revue les conditions préalables dont vous aurez besoin pour suivre ce tutoriel. Au plaisir de vous y retrouver !
Conditions préalables
Avant de nous plonger dans la construction de notre scraper, il y a quelques éléments à mettre en place. Dans cette section, nous verrons comment installer Scrapy et mettre en place un environnement virtuel pour notre projet. La documentation de Scrapy suggère d'installer Scrapy dans un environnement virtuel dédié. En faisant cela, vous éviterez tout conflit avec les paquets de votre système.
Je fais tourner Scrapy sur Ubuntu 22.04.1 WSL (Windows Subsystem for Linux), je vais donc configurer un environnement virtuel pour ma machine.
Je vous encourage à lire le chapitre "Comprendre la structure des dossiers" pour bien comprendre les outils avec lesquels nous travaillons. Jetez également un coup d'œil au chapitre "Scrapy Shell", il rendra votre expérience de développement beaucoup plus facile.
Mise en place d'un environnement virtuel Python
Pour mettre en place un environnement virtuel pour Python dans Ubuntu, vous pouvez utiliser la commande mkvirtualenv. Tout d'abord, assurez-vous que virtualenv et virtualenvwrapper sont installés :
sudo apt-get install virtualenv virtualenvwrapper
Ajoutez ces lignes à la fin de votre fichier .bashrc :
export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/Deve
export VIRTUALENVWRAPPER_PYTHON='/usr/bin/python3'
source /usr/local/bin/virtualenvwrapper.sh
J'ai utilisé Vim pour éditer le fichier, mais vous pouvez choisir l'éditeur de votre choix :
vim ~/.bashrc
// Utilisez ctr + i pour entrer dans le mode insertion, utilisez la flèche vers le bas pour aller au bas du fichier.
// Collez les lignes à la fin du fichier.
// Appuyez sur escape pour quitter le mode insertion, tapez wq et appuyez sur enter pour sauvegarder les changements et quitter Vim.
Créez ensuite un nouvel environnement virtuel avec mkvirtualenv :
$ mkvirtualenv scrapy_env
Vous devriez maintenant voir un (scrapy_env) ajouté au début de votre ligne de terminal.
Pour quitter l'environnement virtuel, tapez $ deactivate
Pour revenir à l'environnement virtuel scrappy_env, tapez $ workon scrapy_env
Installation de Scrapy
Vous pouvez installer Scrapy avec le gestionnaire de paquets pip :
pip install scrapy
Ceci installera la dernière version de Scrapy.
Vous pouvez créer un nouveau projet avec la commande scrapy startproject :
scrapy startproject myproject
Ceci initialisera un nouveau projet Scrapy appelé "myproject". Il doit contenir la structure du projet par défaut.
Comprendre la structure des dossiers
Il s'agit de la structure de projet par défaut :
myproject
├── myproject
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ └── __init__.py
└── scrapy.cfg
items.py
items.py est un modèle pour les données extraites. Ce modèle sera utilisé pour stocker les données que vous extrayez du site web.
Exemple :
import scrapy
class Product(scrapy.Item) :
name = scrapy.Field()
price = scrapy.Field()
description = scrapy.Field()
Nous avons défini ici un élément appelé Produit. Il peut être utilisé par un Spider (voir /spiders) pour stocker des informations sur le nom, le prix et la description d'un produit.
/araignées
/spiders est un dossier contenant les classes Spider. Dans Scrapy, les Spiders sont des classes qui définissent comment un site web doit être scrappé.
Exemple :
import scrapy
from myproject.items import Product
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['<example_website_url>']
def parse(self, response):
# Extract the data for each product
for product_div in response.css('div.product'):
product = Product()
product['name'] = product_div.css('h3.name::text').get()
product['price'] = product_div.css('span.price::text').get()
product['description'] = product_div.css('p.description::text').get()
yield product
Le "spider" parcourt les start_urls, extrait le nom, le prix et la description de tous les produits trouvés sur les pages (en utilisant des sélecteurs css) et stocke les données dans le Product Item (voir items.py). Il "produit" ensuite ces éléments, ce qui amène Scrapy à les transmettre au composant suivant dans le pipeline (voir pipelines.py).
Yield est un mot-clé de Python qui permet à une fonction de renvoyer une valeur sans mettre fin à la fonction. Au lieu de cela, il produit la valeur et suspend l'exécution de la fonction jusqu'à ce que la valeur suivante soit demandée.
Par exemple :
def count_up_to(max):
count = 1
while count <= max:
yield count
count += 1
for number in count_up_to(5):
print(number)
// returns 1 2 3 4 5 (each on a new line)
pipelines.py
Les pipelines sont responsables du traitement des éléments (voir items.py et /spiders) qui sont extraits par les spiders. Vous pouvez les utiliser pour nettoyer le HTML, valider les données et les exporter dans un format personnalisé ou les enregistrer dans une base de données.
Exemple :
import pymongo
class MongoPipeline(object) :
def __init__(self) :
self.conn = pymongo.MongoClient('localhost', 27017)
self.db = self.conn['mydatabase']
self.product_collection = self.db['products']
self.other_collection = self.db['other']
def process_item(self, item, spider) :
if spider.name == 'product_spider' :
//insère l'élément dans la collection de produits
elif spider.name == 'other_spider' :
//insère l'article dans la collection other_collection
return item
Nous avons créé un pipeline nommé MongoPipeline. Il se connecte à deux collections MongoDB (product_collection et other_collection). Le pipeline reçoit des éléments (voir items.py) des spiders (voir /spiders) et les traite dans la fonction process_item. Dans cet exemple, la fonction process_item ajoute les éléments à leurs collections désignées.
settings.py
settings.py stocke une variété de paramètres qui contrôlent le comportement du projet Scrapy, tels que les pipelines, les middlewares et les extensions qui doivent être utilisés, ainsi que les paramètres liés à la façon dont le projet doit gérer les requêtes et les réponses.
Par exemple, vous pouvez l'utiliser pour définir l'ordre d'exécution des pipelines (voir pipelines.py) :
ITEM_PIPELINES = {
'myproject.pipelines.MongoPipeline': 300,
'myproject.pipelines.JsonPipeline': 302,
}
// MongoPipeline will execute before JsonPipeline, because it has a lower order number(300)
Ou définir un conteneur d'exportation :
FEEDS = {
'items': {'uri': 'file:///tmp/items.json', 'format': 'json'},
}
// this will save the scraped data to a items.json
scrappy.cfg
scrapy.cfg est le fichier de configuration des principaux paramètres du projet.
[settings]
default = [name of the project].settings
[deploy]
#url = http://localhost:6800/
project = [name of the project]
middlewares.py
Il existe deux types d'intermédiaires dans Scrapy : les intermédiaires de téléchargement et les intermédiaires d'araignée.
Les logiciels intermédiaires de téléchargement sont des composants qui peuvent être utilisés pour modifier les demandes et les réponses, gérer les erreurs et mettre en œuvre une logique de téléchargement personnalisée. Ils se situent entre le spider et le downloader Scrapy.
Les logiciels intermédiaires de l'araignée sont des composants qui peuvent être utilisés pour mettre en œuvre une logique de traitement personnalisée. Ils se situent entre le moteur et l'araignée.
La coquille de ferraille
Avant de nous lancer dans l'aventure passionnante de l'implémentation de notre scraper de dictionnaires urbains, nous devons d'abord nous familiariser avec le Scrapy Shell. Cette console interactive nous permet de tester notre logique de scraping et de voir les résultats en temps réel. C'est une sorte de bac à sable virtuel où nous pouvons jouer et peaufiner notre approche avant de lâcher notre Spider sur le web. Croyez-moi, cela vous fera gagner beaucoup de temps et vous évitera des maux de tête à long terme. Alors, amusons-nous un peu et faisons connaissance avec le Scrapy Shell.
Ouverture de la coquille
Pour ouvrir le Scrapy Shell, vous devez d'abord naviguer dans le répertoire de votre projet Scrapy dans votre terminal. Ensuite, vous pouvez simplement exécuter la commande suivante :
coquille scrapy
Cela ouvrira le shell Scrapy et vous serez confronté à une invite où vous pourrez saisir et exécuter des commandes Scrapy. Vous pouvez également passer une URL comme argument à la commande du shell pour récupérer directement une page web, comme ceci :
scrapy shell <url>
Par exemple :
scrapy shell https://www.urbandictionary.com/define.php?term=YOLO
Renverra (dans l'objet réponse) le html de la page web qui contient les définitions du mot YOLO (dans le Dictionnaire Urbain).
Une fois dans l'interpréteur de commandes, vous pouvez également utiliser la commande fetch pour récupérer une page web.
fetch('https://www.urbandictionary.com/define.php?term=YOLO')
Vous pouvez également lancer l'interpréteur de commandes avec le paramètre nolog pour qu'il n'affiche pas les journaux :
scrapy shell --nolog
Travailler avec le shell
Dans cet exemple, j'ai récupéré l'URL "https://www.urbandictionary.com/define.php?term=YOLO" et j'ai enregistré le code html dans le fichier test_output.html.
(scrapy_env) mihai@DESKTOP-0RN92KH:~/myproject$ scrapy shell --nolog
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x7f1eef80f6a0>
[s] item {}
[s] settings <scrapy.settings.Settings object at 0x7f1eef80f4c0>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>> response // response is empty
>>> fetch('https://www.urbandictionary.com/define.php?term=YOLO')
>>> response
<200 https://www.urbandictionary.com/define.php?term=Yolo>
>>> with open('test_output.html', 'w') as f:
... f.write(response.text)
...
118260
Inspectons maintenant test_output.html et identifions les sélecteurs dont nous avons besoin pour extraire les données de notre scraper Urban Dictionary.

Nous pouvons l'observer :
- Chaque conteneur de définition de mot possède la classe "definition".
- La signification du mot se trouve à l'intérieur de la div avec la classe "meaning".
- Les exemples du mot se trouvent à l'intérieur de la div avec la classe "exemple".
- Les informations relatives à l'auteur et à la date du message se trouvent dans la div avec la classe "contributeur".
Testons maintenant quelques sélecteurs dans le Scrapy Shell :
Pour obtenir des références à chaque conteneur de définition, nous pouvons utiliser des sélecteurs CSS ou XPath :
Pour en savoir plus sur les sélecteurs XPath, cliquez ici : https://www.webscrapingapi.com/the-ultimate-xpath-cheat-sheet
definitions = response.css('div.definition')
definitions = response.xpath('//div[contains(@class, "definition")]')
Nous devrions extraire la signification, l'exemple et les informations sur le poste de chaque conteneur de définition. Testons quelques sélecteurs avec le premier conteneur :
>>> first_def = definitions[0]
>>> meaning = first_def.css('div.meaning').xpath(".//text()").extract()
>>> meaning
['Yolo', 'means', ', '', 'You Only Live Once', ''.']
>>> meaning = "".join(meaning)
>>> meaning
'Yolo signifie 'On ne vit qu'une fois''
>>> example = first_def.css('div.example').xpath(".//text()").extract()
>>> example = "".join(example)
>>> example
'"Mettez votre ceinture de sécurité". Jessica dit.\r "HAH, YOLO !" Répond Anna.\r(Elles procèdent ensuite à un accident de voiture. Longue histoire courte...Mets ta ceinture de sécurité.)'
>>> post_data = first_def.css('div.contributor').xpath(".//text()").extract()
>>> post_data
['by', 'Soy ugly', ' April 24, 2019']
En utilisant le shell Scrapy, nous avons pu trouver rapidement un sélecteur général qui répond à nos besoins.
definition.css('div.<meaning|example|contributor>').xpath(".//text()").extract()
// returns an array with all the text found inside the <meaning|example|contributor>
ex: ['Yolo ', 'means', ', '', 'You Only Live Once', ''.']
Pour en savoir plus sur les sélecteurs Scrapy, consultez la documentation. https://docs.scrapy.org/en/latest/topics/selectors.html
Mise en œuvre du scraper du dictionnaire urbain
Bon travail ! Maintenant que vous avez pris l'habitude d'utiliser le shell Scrapy et que vous comprenez le fonctionnement interne d'un projet Scrapy, il est temps de vous plonger dans l'implémentation de notre scraper de dictionnaires urbains. À ce stade, vous devriez vous sentir confiant et prêt à assumer la tâche d'extraire toutes ces définitions de mots hilarantes (et parfois douteuses) du Web. Alors sans plus attendre, commençons à construire notre scraper !
Définition d'un élément
Tout d'abord, nous allons implémenter un élément : (voir items.py)
class UrbanDictionaryItem(scrapy.Item) :
meaning = scrapy.Field()
author = scrapy.Field()
date = scrapy.Field()
example = scrapy.Field()
Cette structure contiendra les données extraites de l'araignée.
Définir une araignée
C'est ainsi que nous définirons notre Spider (voir /spiders) :
import scrapy
from ..items import UrbanDictionaryItem
classe UrbanDictionarySpider(scrapy.Spider) :
name = 'urban_dictionary'
start_urls = ['https://www.urbandictionary.com/define.php?term=Yolo']
def parse(self, response) :
definitions = response.css('div.definition')
pour la définition dans les définitions :
item = UrbanDictionaryItem()
item['meaning'] = definition.css('div.meaning').xpath(".//text()").extract()
item['example'] = definition.css('div.example').xpath(".//text()").extract()
author = definition.css('div.contributor').xpath(".//text()").extract()
item['date'] = auteur[2]
item['auteur'] = auteur[1]
élément de rendement
Pour lancer l'araignée urban_dictionary, utilisez la commande suivante :
scrapy crawl urban_dictionary
// les résultats devraient apparaître dans la console (très probablement en haut des logs)
Création d'un pipeline
À ce stade, les données ne sont pas nettoyées.
{'author': 'Soy ugly',
'date': ' April 24, 2019',
'example': ['“Put your ',
'seatbelt',
' on.” Jessica said.\n',
'“HAH, YOLO!” Replies Anna.\n',
'(They then proceed to have a ',
'car crash',
'. ',
'Long story short',
'...Wear a seatbelt.)'],
'meaning': ['Yolo ', 'means', ', ‘', 'You Only Live Once', '’.']}
Nous voulons modifier les champs "example" et "meaning" pour qu'ils contiennent des chaînes de caractères et non des tableaux. Pour ce faire, nous allons écrire un pipeline (voir pipelines.py) qui transformera les tableaux en chaînes de caractères en concaténant les mots.
class SanitizePipeline :
def process_item(self, item, spider) :
# Assainissement du champ 'signification'
item['signification'] = "".join(item['signification'])
# Assainissement du champ 'exemple'
item['exemple'] = "".join(item['example'])
# Assainissement du champ 'date'
item['date'] = item['date'].strip()
return item
//ex : ['Yolo ', 'means', ', '', 'You Only Live Once', ''.'] devient
'Yolo means, 'You Only Live Once'.'
Mise en place du pipeline
Après avoir défini le pipeline, nous devons l'activer. Si nous ne le faisons pas, nos objets UrbanDictionaryItem ne seront pas nettoyés. Pour ce faire, ajoutez-le à votre fichier settings.py (voir settings.py) :
ITEM_PIPELINES = {
'myproject.pipelines.SanitizePipeline': 1,
}
Pendant que vous y êtes, vous pouvez également spécifier un fichier de sortie dans lequel les données extraites seront placées.
FEEDS = {
'items': {'uri': 'file:///tmp/items.json', 'format': 'json'},
}
// this will put the scraped data in an items.json file.
Facultatif : mise en œuvre d'un Proxy Middleware
Le web scraping peut s'avérer un peu pénible. L'un des principaux problèmes que nous rencontrons souvent est que de nombreux sites web nécessitent l'utilisation de javascript pour afficher pleinement leur contenu. Cela peut nous poser d'énormes problèmes en tant que web scrapers, car nos outils n'ont souvent pas la capacité d'exécuter le javascript comme le fait un navigateur web normal. Cela peut conduire à l'extraction de données incomplètes ou, pire encore, au bannissement de notre IP du site web pour avoir effectué trop de requêtes dans un court laps de temps.
Notre solution à ce problème est WebScrapingApi. Avec notre service, vous pouvez simplement faire des requêtes à l'API et elle se chargera de tout le travail pour vous. Il exécutera le JavaScript, fera tourner les proxies et gérera même les CAPTCHA, ce qui vous permettra de gratter facilement les sites web les plus tenaces.
Un intergiciel proxy transmettra chaque demande de récupération faite par Scrapy au serveur proxy. Le serveur proxy effectuera alors la requête pour nous et renverra le résultat.
Tout d'abord, nous allons définir une classe ProxyMiddleware dans le fichier middlewares.py.
import base64
class ProxyMiddleware:
def process_request(self, request, spider):
# Set the proxy for the request
request.meta['proxy'] = "http://proxy.webscrapingapi.com:80"
request.meta['verify'] = False
# Set the proxy authentication for the request
proxy_user_pass = "webscrapingapi.proxy_type=residential.render_js=1:<API_KEY>"
encoded_user_pass = base64.b64encode(proxy_user_pass.encode()).decode()
request.headers['Proxy-Authorization'] = f'Basic {encoded_user_pass}'
Dans cet exemple, nous avons utilisé le serveur proxy WebScrapingApi.
webscrapingapi.proxy_type=residential.render_js=1 is the proxy authentication username, <API_KEY> the password.
Vous pouvez obtenir une clé API gratuite en créant un nouveau compte à l'adresse https://www.webscrapingapi.com/.
Après avoir défini le ProxyMiddleware, il suffit de l'activer en tant que DOWNLOAD_MIDDLEWARE dans le fichier settings.py.
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.ProxyMiddleware': 1,
}
Et c'est tout. Comme vous pouvez le constater, le web scraping avec Scrapy peut simplifier une grande partie de notre travail.
Conclusion
Nous avons réussi ! Nous avons construit un scraper capable d'extraire des définitions de Urban Dictionary et nous avons beaucoup appris sur Scrapy en cours de route. De la création d'éléments personnalisés à l'utilisation de middlewares et de pipelines, nous avons prouvé à quel point le web scraping avec Scrapy peut être puissant et polyvalent. Et le meilleur ? Il reste encore beaucoup à découvrir.
Félicitations pour être arrivé au bout de ce voyage avec moi. Vous devriez maintenant avoir confiance en votre capacité à vous attaquer à n'importe quel projet de web scraping qui se présentera à vous. N'oubliez pas que le web scraping n'est pas nécessairement intimidant ou accablant. Avec les bons outils et les bonnes connaissances, il peut s'agir d'une expérience amusante et enrichissante. Si vous avez besoin d'un coup de main, n'hésitez pas à nous contacter à l'adresse https://www.webscrapingapi.com/. Nous connaissons bien le web scraping et nous sommes plus qu'heureux de vous aider de quelque manière que ce soit.
Nouvelles et mises à jour
Restez au courant des derniers guides et nouvelles sur le web scraping en vous inscrivant à notre lettre d'information.
We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Articles connexes

Explorez les complexités du scraping des données de produits Amazon avec notre guide approfondi. Des meilleures pratiques aux outils tels que l'API Amazon Scraper, en passant par les considérations juridiques, apprenez à relever les défis, à contourner les CAPTCHA et à extraire efficacement des informations précieuses.


Explorez la comparaison approfondie entre Scrapy et Selenium pour le web scraping. De l'acquisition de données à grande échelle à la gestion de contenus dynamiques, découvrez les avantages, les inconvénients et les caractéristiques uniques de chacun. Apprenez à choisir le meilleur framework en fonction des besoins et de l'échelle de votre projet.


Apprenez à récupérer des sites web dynamiques en JavaScript à l'aide de Scrapy et de Splash. De l'installation à l'écriture d'un spider, en passant par la gestion de la pagination et des réponses Splash, ce guide complet propose des instructions pas à pas pour les débutants comme pour les experts.
