Simple scraping python : un script pour faire du web scraping

  • | Développement
Simple Scraping Python

Je vous propose aujourd'hui de découvrir Python au travers du petit script Simple Scraping Python qui permet de faire du web scraping sur un site web. Mais qu'est ce que le web scraping? Il s'agit d'une technique qui consiste à télécharger le contenu d'une page web et la parser pour en extraire son contenu. Le web scraping peut être utile sur ses propres sites web pour par exemple vérifier la structuration des pages ou sur des sites tiers pour faire de la veille, ou vérifier la concurrence des prix par exemple. 
Attention toutefois, à ne pas récupérer de données privées ou protégées...

A travers ce petit script on va voir :

  1. Comment web scraper un contenu?
  2. Comment générer un fichier csv avec les données récupérées?
  3. Comment afficher les données récupérées dans la console?

Installation de Simple Scraping Python

Les sources du projet sur Github : https://github.com/fonkyju/simple-scraping-python

Le script tourne sous Python et la version 3.9.4, pour l'installer sous Mac on peut passer par Brew.

Une fois python installé, on installe le programme avec la commande suivante : 

pip install -r requirements.txt

Ce qui va télécharger toutes les dépendances du script.

Pour les besoins du programme et pour ne pas crawler un site sur le web, j'ai créé un vhost en local qui me permet de simuler la récupération d'un site.

Les paramètres suivants sont liés au vhost : 

host            = "http://www.monsite.fr/"
directory       = "annonces/"
mySearches      = ["informatique.html", "multimedia.html"]
maxResults      = 2 # default pagination number

host : l'adresse de mon vhost
directory : la simulation d'une catégorie d'un site
mySearches : les différentes pages web que je veux crawler
maxResults : le nombre de page sur la pagination des pages à crawler

 

Une fois l'installation terminée, on lance le programme avec la commande suivante : 

python3 main.py

 

Vous devriez voir le résultat suivant : 

Exécution de simple scraping python

 

 

1. Comment web scraper un contenu?

Pour récupérer le contenu et le parser/extraire dans Simple Scraping Python, on va utiliser respectivement les librairies requests (pour envoyer une requête http et en récupérer le contenu) et BeautifulSoup (pour extraire des données dans le contenu récupéré).

Voici la première partie du code qui permet d'extraire le contenu :

import requests
import bs4
from bs4 import BeautifulSoup
import pandas as pd
import time
from rich import print
from rich.console import Console
from rich.table import Table

from function import extract_id, extract_published, extract_title, extract_city, extract_price, extract_url

# general parameters
host            = "http://www.monsite.fr/"
directory       = "annonces/"
mySearches      = ["informatique.html", "multimedia.html"]
maxResults      = 2 # default pagination number
announcements   = []

# extract file parameters
columns = ["id", "publie", "titre", "ville", "prix", "url"]
sample_df = pd.DataFrame(columns = columns)


# scrapping code
# iterate on mySearches
for mySearch in mySearches:

  # generate mySearch Url
  urlToCrawl = host+directory+mySearch

  # iterate on pagination if exists
  for start in range(0, maxResults, 1):
      urlToCrawlWithPagination = urlToCrawl+'?page=' + str(start)
      print("Get Url : " + urlToCrawlWithPagination)

      page = requests.get(urlToCrawlWithPagination)
      time.sleep(1)  #ensuring at least 1 second between page grabs
      #soup = BeautifulSoup(page.text, "lxml", from_encoding="utf-8")
      soup = BeautifulSoup(page.text, "lxml")

      # get all announcements from page variable
      for div in soup.find_all(name="div", attrs={"class":"row"}):

        #creating an empty list to hold the data for each posting
        announcement = []

        #get id, published, title, city, price, url from announcement
        announcement.append(extract_id(div))
        announcement.append(str(extract_published(div)) + " jour(s)")
        announcement.append(extract_title(div))
        announcement.append(extract_city(div))
        announcement.append(str(extract_price(div)) + " €")
        announcement.append(host + extract_url(div))

        # check if announcement is already saved

        if(announcement not in announcements):
          announcements.append(announcement)

Ici on peut vraiment tout customiser pour s'adapter au site cible.

Que fait ce programme : 

  • il fait une double boucle pour générer les urls à crawler : la 1ere correspond aux pages cibles, la 2nd à la pagination.
  • ensuite grace à la librairie requests on lance la requête http et on récupère le contenu. Au passage je mets un petit délai d'attente même si en local ça n'a pas d'importance, sur un site web il arrive fréquemment qu'on soit blacklisté si on veut crawler trop vite!
  • puis on instancie un objet BeautifulSoup avec le résultat de requests. Cet objet va nous permettre d'utiliser des méthodes qui vont nous simplifier la vie.
  • dans la boucle for suivante on fait notre première recherche d'extraction sur des div avec la class="row" : ce qui correspond aux annonces qu'on veut récupérer.
  • puis on va remplir un tableau avec toutes les informations extraites. Ici on va créer des fonctions dans un autre fichier qui vont nous permettre de simplifier le fichier main.py et également de créer des tests sur nos fonctions.
  • le dernier if permet de ne pas ajouter l'annonce si elle existe déjà dans notre tableau. 

 

Voici le contenu du fichier function.py de Simple Scraping Python dans lequel on retrouve toutes les fonctions d'extraction :

# function.py

import regex

#####################
# extract_id function
#####################
def extract_id(div):
  try:
    target = div.find("a", attrs={"class": "title"})
    return target['id']
  except:
    return "Nothing_found"

#####################
# extract_published function
#####################
def extract_published(div):
  try:
    target = div.find("span", attrs={"class": "published"})

    today = regex.search(r"(nouveau)", target.text)

    if(today):
      day = 0
    else :
        otherday = [int(i) for i in target.text.split() if i.isdigit()]
        if(otherday):
          day = otherday[0]

    return day
  except:
    return "Nothing_found"

#####################
# extract_title function
#####################
def extract_title(div):
  try:
    target = div.find(name="a", attrs={"class":"title"})
    return target.text.strip()
  except:
    return "Nothing_found"


#####################
# extract_city function
#####################
def extract_city(div):
  try:
    target = div.find(name="div", attrs={"class":"location"})
    return target.text.strip()
  except:
    return "Nothing_found"


#####################
# extract_price function
#####################
def extract_price(div):
  try:
    target = div.find(name="span", attrs={"class":"price"})
    price = [int(i) for i in target.text.split() if i.isdigit()]
    return price[0]
  except:
    return "Nothing_found"

#####################
# extract_title function
#####################
def extract_url(div):
  try:
    target = div.find(name="a", attrs={"class":"title"})
    return target['href']
  except:
    return "Nothing_found"

 

Sur chaque fonction, on passe en paramètre une annonce et on va chercher et extraire une donnée précise.

Typiquement pour la fonction juste au dessus extract_price on va chercher un span qui aura une class="price" et ensuite on vient extraire le contenu uniquement numérique de cette zone.

C'est le même principe pour les autres fonctions.

A ce niveau on crawl les pages souhaitées, on extrait les données et on met ces informations dans un tableau announcements.

Voyons comment on va créer un fichier csv avec ces datas.

 

2. Comment générer un fichier csv avec les données récupérées?

On a récupéré nos datas dans le paragraphe précédent et on les a glissé dans un tableau. On va maintenant transformer ce tableau en fichier csv.

Pour générer ce fichier, on va utiliser la librairie Pandas. Cette librairie est très utilisée en IA pour faire des analyses de données mais honte à nous on va juste l'utiliser pour faire un csv! :D

Voici le code qu'on ajoute au main.py :

# extract file parameters
columns = ["id", "publie", "titre", "ville", "prix", "url"]
sample_df = pd.DataFrame(columns = columns)

....

# generate csv files
if(len(announcements) > 0):
  for announcement in announcements:
    num = (len(sample_df) + 1)
    sample_df.loc[num] = announcement

  sample_df.to_csv("extract.csv", encoding="utf-8")

Que fait on dans ce morceau de code : 

  • on ajoute le nom des colonnes pour notre csv et on les instancie par un objet pd alias de pandas.
  • on vérifie qu'on a des résultats
  • puis dans une boucle on itère sur le tableau pour ajouter chaque ligne
  • enfin on transforme cet objet en fichier csv!

Une fois ces données en csv on peut les réimporter, les retravailler, constituer des graphes, etc...

 

3. Comment afficher les données récupérées dans la console?

Avoir un fichier avec les datas c'est bien si on a beaucoup d'informations ou de lignes. En revanche si on recherche sur un site quelque chose de précis on va crawler beaucoup de page mais le résultat peut être très succinct. Dans ce cas on peut privilégier l'affichage directement dans son terminal.

Pour faire cela on va utiliser la librairie Rich spécialisée dans l'affichage des résultats. Cette lib est vraiment génial puisqu'on va pouvoir coloriser, customiser les logs, customiser le debug, faire des tableaux, des progress bars, des status, des interactions, etc...

Pour afficher le tableau résultat de notre script, on ajoute la partie de code suivante : 

# Display results in console
if(len(announcements) > 0):

  table = Table()
  table.add_column("ID", justify="right", style="cyan", no_wrap=True)
  table.add_column("PUBLIE", justify="right", style="cyan", no_wrap=True)
  table.add_column("TITRE", style="magenta")
  table.add_column("VILLE", justify="left", style="green")
  table.add_column("PRIX", justify="right", style="green")
  table.add_column("URL", justify="left", style="green")

  for announcement in announcements:
    table.add_row(announcement[0], announcement[1], "[bold red]" + announcement[2] + "[/]", announcement[3], announcement[4], announcement[5])

  console = Console()
  console.print(table)

Ce que fait ce code : 

  • on vérifie qu'il y a des résultats à afficher dans announcements
  • on crée un objet table
  • on ajoute les colonnes souhaitées
  • puis on boucle sur le tableau announcements
  • enfin on print le tableau dans la console

Résultat : on a un beau tableau qui présente les résultats et cela nous a pris 12 lignes.

 

En conclusion, j'espère que ce script Simple Scraping Python vous aura aidé ou donné envie de vous mettre à Python! ;)

L'auteur de cet article
Julien Krier
Responsable Digital, ayant occupé différents postes en informatique depuis 2001, Julien Krier a travaillé sur de multiples plateformes, sites de contenu ou e-commerce à fort trafic. Il est spécialisé dans les technologies web sur les CMS comme Drupal 7 ou Drupal 8 et les Framework Php comme Symfony 5.
Cet article vous a aidé?
Average: 5 (1 vote)
Partagez cet article
Articles sur le même sujet
Tests et intégration continue avec CircleCIComment mettre en place des tests et une intégration continue avec CircleCI? Exemple de configuration sur un script en Python.