Le framework Scrapy est un outil puissant pour l'extraction de données à partir de sites web, offrant une flexibilité pour collecter diverses informations, des images aux données financières complexes. Cet article explore des applications pratiques de Scrapy, démontrant son utilisation pour l'extraction d'images, de données boursières et de taux de change, avec un accent sur la gestion de la concurrence et la persistance des données dans une base de données MySQL.
Collecte d'Images à Grande Échelle
L'extraction d'images depuis un site web est une tâche courante en web scraping. L'implémentation ci-dessous utilise Scrapy pour naviguer à travers les pages d'un site et télécharger un nombre défini d'images, tout en contrôlant la profondeur de la navigation.
Pour éviter de surcharger le serveur cible et pour une gestion efficace des ressources, des limites sont mises en place pour le nombre total de pages à visiter et le volume d'images à télécharger. Le framework Scrapy permet également de configurer des paramètres de concurrence pour optimiser la vitesse de récupération.
import scrapy
class ImageScraperSpider(scrapy.Spider):
name = 'extracteur_images'
# Paramètres de contrôle pour limiter la collecte
pages_max = 5 # Nombre maximal de pages à parcourir
images_max = 142 # Nombre maximal d'images à télécharger
compteur_images = 0 # Compteur d'images actuellement téléchargées
page_actuelle = 1 # Suivi de la page en cours
start_urls = ['https://p.weather.com.cn/tqxc/index.shtml'] # URL de départ à adapter
def parse(self, response):
# Localisation des URLs d'images via sélecteurs CSS
urls_images = response.css('img::attr(src)').getall()
for url_img in urls_images:
if self.compteur_images >= self.images_max:
break # Arrêt si le quota d'images est atteint
self.compteur_images += 1
yield {
'url_image': url_img # L'Item 'url_image' sera traité par un Pipeline d'images
}
# Logique pour naviguer vers la page suivante
if self.page_actuelle < self.pages_max and self.compteur_images < self.images_max:
self.page_actuelle += 1
url_prochaine_page = f'https://p.weather.com.cn/tqxc/index_{self.page_actuelle}.shtml'
yield response.follow(url_prochaine_page, self.parse)
def closed(self, reason):
self.logger.info(f'Total images extraites : {self.compteur_images}')
# Pour la configuration multi-threading (dans settings.py de Scrapy) :
# CONCURRENT_REQUESTS = 16 # Nombre de requêtes concurrentes maximales
# DOWNLOAD_DELAY = 0.5 # Délai entre les requêtes pour éviter la surcharge
La gestion de la concurrence est cruciale pour une collecte efficace. En ajustant les paramètres CONCURRENT_REQUESTS et DOWNLOAD_DELAY dans les réglages de Scrapy (settings.py), il est possible d'optimiser la vitesse d'extraction tout en respectant la politique d'utilisation des serveurs cibles.
Collecte et Persistance de Données Boursières
L'extraction de données financières, telles que les cours boursiers, nécessite souvent de traiter des structures de données complexes comme le JSON. Scrapy, combiné à l'utilisation d'Item pour structurer les données et de Pipeline pour la persistance, offre une solution robuste.
Les données sont d'abord extraites d'une réponse de type JSONP (JSON avec padding), puis converties en objets Python. Chaque ensemble de données de stock est ensuite mappé à un StockItem, qui est transmis aux Pipelines pour le stockage.
import scrapy
import json
from scrapy import Item, Field
class StockItem(Item):
identifiant = Field() # Code du titre boursier
nom_titre = Field() # Nom de l'entreprise
cours_actuel = Field() # Prix actuel de l'action
variation_prix = Field() # Changement de prix (positif/négatif)
volume_echanges = Field() # Volume des transactions
montant_total_echanges = Field() # Montant total des transactions
pourcentage_variation = Field() # Pourcentage de variation du prix
class StockScraperSpider(scrapy.Spider):
name = 'extracteur_actions'
start_urls = ['http://push2.eastmoney.com/api/qt/clt/count'] # Exemple d'URL, à adapter
def parse(self, response):
# Le contenu est souvent au format JSONP, nécessitant un pré-traitement
try:
json_str_start = response.text.index('(') + 1
json_str_end = response.text.rindex(')')
json_data_raw = response.text[json_str_start:json_str_end]
data = json.loads(json_data_raw)
except (ValueError, IndexError, json.JSONDecodeError) as e:
self.logger.error(f"Erreur de traitement JSON: {e} dans {response.url}")
return
if 'data' in data and 'diff' in data['data']:
for detail_action in data['data']['diff']:
item = StockItem()
item['identifiant'] = detail_action.get('f12')
item['nom_titre'] = detail_action.get('f14')
item['cours_actuel'] = detail_action.get('f2')
item['variation_prix'] = detail_action.get('f4')
item['volume_echanges'] = detail_action.get('f5')
item['montant_total_echanges'] = detail_action.get('f6')
item['pourcentage_variation'] = detail_action.get('f10')
yield item
else:
self.logger.warning("Structure de données boursières inattendue ou champ 'diff' manquant.")
L'intégration de ces données dans une base de données relationnelle comme MySQL via un Pipeline Scrapy permet de stocker, interroger et analyser efficacement les informations financières collectées. Cela transforme les données brutes extraitse en une ressource structurée et utilisable.
Extraction de Taux de Change avec XPath et Stockage MySQL
Pour les sites web où les données sont présentées dans des tableaux HTML classsiques, l'utilisation de sélecteurs XPath est particulièrement efficace. Cette méthode est illustrée par l'extraction des taux de change à partir du site de la Banque de Chine.
Chaque ligne du tableau est itérée, et des expressions XPath précises sont utilisées pour cibler les cellules (<td>) correspondant à des informations spécifiques telles que la devise, les prix d'achat/vente, et la date de publication. Ces données sont ensuite encapsulées dans un ForeignExchangeItem.
import scrapy
from scrapy import Item, Field
class ForeignExchangeItem(Item):
devise = Field() # Nom de la devise
prix_achat = Field() # Prix d'achat (moyen)
prix_achat_comptant = Field() # Prix d'achat au comptant
prix_vente = Field() # Prix de vente (moyen)
prix_vente_comptant = Field() # Prix de vente au comptant
prix_conversion = Field() # Prix de conversion
date_publication = Field() # Date de publication du taux
heure_publication = Field() # Heure de publication du taux
class ExchangeRateSpider(scrapy.Spider):
name = "extracteur_taux_change"
allowed_domains = ["boc.cn"]
start_urls = ["https://www.boc.cn/sourcedb/whpj/"] # URL de la Banque de Chine
def parse(self, response):
# Cibler les lignes du tableau des taux de change, en ignorant l'en-tête
lignes_tableau = response.xpath('//table//tr[position()>1]')
for ligne in lignes_tableau:
item = ForeignExchangeItem()
item['devise'] = ligne.xpath('./td[1]/text()').get()
item['prix_achat'] = ligne.xpath('./td[2]/text()').get()
item['prix_achat_comptant'] = ligne.xpath('./td[3]/text()').get()
item['prix_vente'] = ligne.xpath('./td[4]/text()').get()
item['prix_vente_comptant'] = ligne.xpath('./td[5]/text()').get()
item['prix_conversion'] = ligne.xpath('./td[6]/text()').get()
item['date_publication'] = ligne.xpath('./td[7]/text()').get()
item['heure_publication'] = ligne.xpath('./td[8]/text()').get()
yield item
Cette approche met en évidence la puissance de XPath pour la navigation et l'extraction de données précises à partir de structures HTML tabulaires, un scénario très courant dans le web scraping d'informations financières ou catalogues.
L'ensemble de ces exemples illustre la polyvalence de Scrapy pour adresser divers besoins de collecte de données. L'utilisation systématique des Items pour la structuration et des Pipelines pour la persistance dans des bases de données comme MySQL est une pratique fondamentale pour construire des solutions de scraping robustes et maintenables.