Les fondamentaux de Scrapy avec exemples pratiques

Scrapy est un framework Python puissant et rapide pour extraire des données de sites web. Ce guide couvre les étapes essentielles pour l'utiliser, de l'installation à l'extraction avancée.

Installation de Scrapy

Scrapy dépend de Twisted, qui est généralement distribué sous forme de package wheel. L'installation se fait donc en plusieurs étapes. Tout d'abord, intsallez l'outil wheel, puis installez Twisted à l'aide du lien correspondant à votre système. Enfin, installez Scrapy lui-même.

pip install wheel
pip install https://download.lfd.uci.edu/pythonlibs/q5gtlas7/Twisted-19.2.0-cp37-cp37m-win_amd64.whl
pip install scrapy

Note : Le fichier .whl pour Twisted doit correspondre à la version de votre Python et à l'architecture de votre système d'exploitation.

Initialisation d'un projet

Pour démarrer un nouveau projet, utilisez la commande startproject. Cela génère la structure de répertoire par défaut.

scrapy startproject mon_projet

Développement d'un spider

Un spider est la classe qui définit comment parcourir un site et extraire les données. Créons un exemple pour extraire des informations de livres depuis une bibliothèque en ligne.

import scrapy
from bs4 import BeautifulSoup
from ..items import BookItem

class BookSpider(scrapy.Spider):
    name = 'livres'
    allowed_domains = ['bibliotheque-en-ligne.fr']
    
    def start_requests(self):
        for page in range(3):
            url = f'https://bibliotheque-en-ligne.fr/populaires?offset={page * 20}'
            yield scrapy.Request(url=url, callback=self.parse_list)

    def parse_list(self, response):
        soup = BeautifulSoup(response.text, 'html.parser')
        entries = soup.select('div.book-card')
        for entry in entries:
            title = entry.select_one('h3.title').text.strip()
            details = entry.select_one('p.meta').text.strip()
            rating = entry.select_one('span.note').text.strip()
            
            item = BookItem()
            item['titre'] = title
            item['details'] = details
            item['note'] = rating
            yield item

Définition des items

La classe Item définit la structure des données que nous voulons collecter.

import scrapy

class BookItem(scrapy.Item):
    titre = scrapy.Field()
    details = scrapy.Field()
    note = scrapy.Field()

Configuration du spider

Le fichier settings.py contient les configurations critiques, comme le User-Agent pour simuler un navigateur et le respect du robots.txt.

BOT_NAME = 'mon_projet'
SPIDER_MODULES = ['mon_projet.spiders']
NEWSPIDER_MODULE = 'mon_projet.spiders'
# Désactiver le respect du robots.txt pour l'extraction
ROBOTSTXT_OBEY = False
# Définir un User-Agent réaliste
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'

Exécution du spider

Le spider peut être lancé directement depuis la ligne de commande ou via un script Python.

# En ligne de commande
scrapy crawl livres

# Via un script main.py
from scrapy import cmdline
cmdline.execute(['scrapy', 'crawl', 'livres'])

Exportation des résultats

Scrapy offre plusieurs façons d'exporter les données extraites.

Vers un fichier CSV : Ajoutez ces paramètres dans settings.py.

FEED_URI = './resultats/%(name)s.csv'
FEED_FORMAT = 'CSV'
FEED_EXPORT_ENCODING = 'utf-8-sig'

Vers un fichier Excel : Cela nécessite la mise en place d'un Item Pipeline. Activez le pipeline dans settings.py.

ITEM_PIPELINES = {
   'mon_projet.pipelines.ExcelPipeline': 300,
}

Ensuite, implémentez le pipeline dans pipelines.py.

import openpyxl

class ExcelPipeline:
    def open_spider(self, spider):
        self.classeur = openpyxl.Workbook()
        self.feille = self.classeur.active
        self.feille.append(['Titre', 'Détails', 'Note'])

    def process_item(self, item, spider):
        ligne = [item['titre'], item['details'], item['note']]
        self.feille.append(ligne)
        return item

    def close_spider(self, spider):
        self.classeur.save('./livres_exportes.xlsx')

Paramètres supplémentaires

Le délai entre les reequêtes peut être contrôlé pour être plus poli envers le serveur.

# Délai aléatoire entre 2 et 5 secondes
DOWNLOAD_DELAY = 3
RANDOMIZE_DOWNLOAD_DELAY = True

Concepts avancés et callback

Pour extraire des données qui nécessitent de naviguer sur plusieurs pages (par exemple, une page de liste puis une page de détail par élément), on utilise le système de callback.

class JobSpider(scrapy.Spider):
    name = 'emplois'
    allowed_domains = ['site-emploi.com']

    def parse(self, response):
        # Traitement de la page de liste des entreprises
        soup = BeautifulSoup(response.text, 'html.parser')
        for link in soup.select('a.company-link'):
            company_url = response.urljoin(link['href'])
            yield scrapy.Request(company_url, callback=self.parse_company)

    def parse_company(self, response):
        # Traitement de la page de détails d'une entreprise
        soup = BeautifulSoup(response.text, 'html.parser')
        company_name = soup.select_one('h1#main-title').text.strip()
        # ... extraction des offres d'emploi ...
        for job in soup.select('div.job-posting'):
            item = JobItem()
            item['entreprise'] = company_name
            item['poste'] = job.select_one('h3').text.strip()
            item['lieu'] = job.select_one('.location').text.strip()
            yield item

Ce modèle ouvre la porte à des requêtes plus complexes, comme la gestion des cookies, l'intégration avec Selenium pour le rendu JavaScript, ou la construction d'architectures distribuées.

Étiquettes: Scrapy Python web scraping BeautifulSoup openpyxl

Publié le 15 juin à 22h07