Web Scraping et Analyse du HTML en Python avec Beautiful Soup

October 22, 2019
Rédigé par
Sam Agnew
Twilion

web-scraping-analyse-html-python-beautiful-soup

Internet offre une incroyable diversité d’informations destinées à la consommation humaine. Mais il est souvent difficile d'accéder à ces données par voie programmatique, si elles ne se présentent pas sous la forme d'une API REST dédiée. Grâce à des outils Python comme Beautiful Soup, vous pouvez récupérer, analyser des pages Web puis utiliser ces données dans vos projets.

Par exemple : Comment récupérer des données MIDI sur Internet pour entraîner un réseau neuronal avec Magenta qui sera capable de générer de la musique rétro Nintendo ?

Nous avons besoin pour cela d'un ensemble de musiques MIDI provenant d'anciens jeux Nintendo. Beautiful Soup nous permet d’obtenir ces données à partir des Video Game Music Archive.

Démarrage et installation des dépendances

Avant de continuer, assurez-vous d’avoir bien installé la mise à jour de Python 3 et de pip. Créez et activez un environnement virtuel avant d'installer toutes les dépendances.

Maintenant, vous pouvez installer la bibliothèque Requests. C’est ce qui servira à effectuer des requêtes HTTP afin d'obtenir les données de la page web et de Beautiful Soup pour analyser le HTML.

Une fois votre environnement virtuel activé, exécutez la commande suivante dans votre terminal :

pip install requests==2.22.0 beautifulsoup4==4.9.3

Bon à savoir : Beautiful Soup 4 est la version la plus récente, la 3 n'étant plus développée ni prise en charge.

Utilisation de Requests pour récupérer des données à analyser avec Beautiful Soup

Il nous faut récupérer le HTML de la page Web. Ecrivez le code ci-dessous pour envoyer une requête GET à la page web que nous voulons, ce qui créera un objet BeautifulSoup avec le HTML de cette page :

import requests
from bs4 import BeautifulSoup

vgm_url = 'https://www.vgmusic.com/music/console/nintendo/nes/'
html_text = requests.get(vgm_url).text
soup = BeautifulSoup(html_text, 'html.parser')

Avec cet objet soup, vous pourrez naviguer et rechercher les données directement dans le HTML.

Par exemple :

  • En exécutant soup.title après le code précédent dans un shell Python, vous obtiendrez le titre de la page Web
  • En entrant print(soup.get_text()), vous pourrez voir le texte entier de ladite page.

Se familiariser avec Beautiful Soup

Pro-tip : les méthodes find() et find_all() sont parmi les armes les plus puissantes de votre arsenal :

  • soup.find() sera idéale pour les cas où vous ne cherchez qu'un seul élément - comme la balise body.

Sur notre page Web, soup.find(id='banner_ad').text vous donnera le texte de l'élément HTML de la bannière publicitaire.

  • soup.find_all() sera la méthode que vous utiliserez le plus dans vos aventures de web scraping. En l’utilisant, vous pouvez parcourir tous les liens hypertextes de la page et imprimer leurs URLs :
for link in soup.find_all('a'):
print(link.get('href'))

Il est possible de fournir différents arguments à find_all, tels que des expressions régulières (regex) ou des attributs de balises pour filtrer précisément ce que vous souhaitez.

Pour plus de fonctionnalités intéressantes, lisez la documentation !

Analyse syntaxique et navigation HTML avec BeautifulSoup

Avant d'écrire plus de code pour analyser le contenu, observons d'abord le HTML rendu par le navigateur.

Chaque page web est différente. L'obtention des bonnes données nécessite un peu de créativité, de reconnaissance des patterns, et d'expérimentations !

capture d'écran des musiques de Castlevenia 3 par ordre alphabétique

Notre but est de télécharger un paquet de fichiers MIDI. Mais beaucoup sont présents en double sur cette page web ainsi que des remixes de chansons. Sauf que nous ne désirons qu'un seul exemplaire de chaque chanson, et comme nous voulons utiliser ces données pour entraîner un réseau neuronal à générer une musique Nintendo juste et précise, il ne faudrait pas l'entraîner sur des versions différentes créées par des utilisateurs.

Lorsque vous élaborez du code pour analyser une page Web,vous pouvez vous servir des outils de développement disponibles dans la plupart des navigateurs modernes.

Faites clic droit sur l'élément qui vous intéresse et vous pourrez inspecter le code HTML qui se cache derrière et déterminer comment accéder aux données que vous souhaitez grâce au code.

inspection du code à l'aide des outils de développement du navigateur

Servons-nous de la méthode find_all pour parcourir tous les liens de la page. Cette fois, nous allons utiliser des expressions régulières pour les filtrer.

Ainsi nous n’obtenons que les liens contenant des fichiers MIDI sans parenthèses dans le texte - ce qui exclut tous les doublons et remixes.

Créez un fichier appelé nes_midi_scraper.py et ajoutez-y le code suivant :

import re
import requests
from bs4 import BeautifulSoup

vgm_url = 'https://www.vgmusic.com/music/console/nintendo/nes/'
html_text = requests.get(vgm_url).text
soup = BeautifulSoup(html_text, 'html.parser')

if __name__ == '__main__':
  attrs = {
    'href': re.compile(r'\.mid$')
  }
 
  tracks = soup.find_all('a', attrs=attrs, string=re.compile(r'^((?!\().)*$'))
 
  count = 0
  for track in tracks:
    print(track)
    count += 1
  print(len(tracks))

Les fichiers MIDI seront filtrés, et cela imprimera la balise de lien correspondante, puis le nombre de fichiers filtrés.

Exécutez ensuite ce code dans votre terminal avec la commande :

python nes_midi_scraper.py

Téléchargement des fichiers MIDI souhaités à partir de la page web

Maintenant que nous avons un code fonctionnel permettant d'itérer à travers tous les fichiers MIDI, nous devons en écrire un autre pour tous les télécharger.

Dans nes_midi_scraper.py, ajoutez une fonction intitulée download_track, et appelez-la dans la boucle qui parcourra toutes les pistes :

import re

import requests
from bs4 import BeautifulSoup

vgm_url = 'https://www.vgmusic.com/music/console/nintendo/nes/'
html_text = requests.get(vgm_url).text
soup = BeautifulSoup(html_text, 'html.parser')

def download_track(count, track_element):
  # Get the title of the track from the HTML element
  track_title = track_element.text.strip().replace('/', '-')
  download_url = '{}{}'.format(vgm_url, track_element['href'])
  file_name = '{}_{}.mid'.format(count, track_title)

  # Download the track
  r = requests.get(download_url, allow_redirects=True)
  with open(file_name, 'wb') as f:
    f.write(r.content)

  # Print to the console to keep track of how the scraping is coming along.
  print('Downloaded: {}'.format(track_title, download_url))

if __name__ == '__main__':
  attrs = {
    'href': re.compile(r'\.mid$')
  }

  tracks = soup.find_all('a', attrs=attrs, string=re.compile(r'^((?!\().)*$'))

  count = 0
  for track in tracks:
    download_track(count, track)
    count += 1
  print(len(tracks))

Dans cette fonction download_track, nous passons l'objet Beautiful Soup représentant l'élément HTML du lien vers le fichier MIDI, avec un numéro unique dans le nom du fichier pour éviter les éventuelles collisions de noms.

Exécutez ce code à partir du répertoire où vous voulez sauvegarder tous les fichiers MIDI. Regardez votre écran de terminal afficher les MIDI que vous avez téléchargés (2230 pour nous au moment de l'écriture de ce tutoriel).

Et ce n'est qu'un exemple concret de la multitude de possibilités qu’offre Beautiful Soup !

impression dans le terminal des fichiers téléchargés

La vaste étendue du World Wide Web

Maintenant que vous pouvez extraire des éléments des pages Web via la programmation, vous avez accès à une énorme source de données pour tous les besoins de vos projets.

A ne pas oublier : si les propriétaires d’une page Web y apportent des modifications, le HTML peut changer. Ce qui veut dire qu’il faudra changer votre manière de le parcourir en mettant à jour votre propre code.

Et maintenant, que faire avec les données que vous venez de récupérer dans les Video Game Music Archive ? Voici quelques suggestions !

J'ai hâte de voir ce que vous allez construire !