Exercice 1 : Scraping du clsasement académique chinois 2020
L'objectif consiste à extraire les données du classement ShanghaiRanking pour l'année 2020 en exploitant les bibliothèques requests et BeautifulSoup.
Impléation complète
import requests
from bs4 import BeautifulSoup
adresse = "http://www.shanghairanking.cn/rankings/bcur/2020"
requete = requests.get(adresse)
requete.encoding = "utf-8"
analyseur = BeautifulSoup(requete.text, "html.parser")
lignes = analyseur.select(".rk-table tbody tr")
print("Rang\tÉtablissement\tProvince\tCatégorie\tScore")
for ligne in lignes:
position = ligne.select_one("td:nth-child(1)").text.strip()
etablissement = ligne.select_one("td:nth-child(2)").text.strip().replace("\n", "").replace(" ", "")
region = ligne.select_one("td:nth-child(3)").text.strip()
categorie = ligne.select_one("td:nth-child(4)").text.strip()
points = ligne.select_one("td:nth-child(5)").text.strip()
print(f"{position}\t{etablissement}\t{region}\t{categorie}\t{points}")
Mécanismes essentiels
La requête HTTP initialise la connexion avec le serveur. L'attribution explicite de l'encodage UTF-8 garantit la lisibilité des caractères chinois. Le sélecteur CSS .rk-table tbody tr isole les rangées pertinentes du tableau, tandis que select_one avec le pseudo-sélecteur nth-child extrait chaque cellule selon son indice positionnel. Un nettoyage textuel élimine les artefacts de formatage.
Exercice 2 : Crawler orienté prix pour produits e-commerce
Ce script récupère les articles correspondant au mot-clé « 书包 » (sac à dos) sur une plateforme de comparaison de prix, avec navigation paginée.
Code source
import requests
import re
import time
def extraire_produits():
domaine = "https://www.meidebi.com"
critere = "书包"
pages_max = 5
entetes = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
try:
verification = requests.get(domaine, headers=entetes, timeout=10)
print("Connexion au site validée.")
except requests.RequestException as err:
print(f"Échec de connexion: {err}")
return
articles = []
indice_page = 1
while indice_page <= pages_max:
url_page = f"{domaine}/Search?keyword={critere}&p={indice_page}"
print(f"Récupération page {indice_page}...")
try:
reponse = requests.get(url_page, headers=entetes, timeout=10)
reponse.raise_for_status()
reponse.encoding = reponse.apparent_encoding
contenu = reponse.text
except requests.RequestException as err:
print(f"Erreur page {indice_page}: {err}")
break
motif = re.compile(
r'<li class="clearfix">.*?'
r'<span class="red price">\s*¥\s*([\d\.]+)\s*</span>.*?'
r'<h6><a href=".*?" target="_blank">(.*?)</a></h6>',
re.DOTALL
)
correspondances = motif.findall(contenu)
if not correspondances:
print(f"Aucun produit détecté page {indice_page}, arrêt.")
break
articles.extend(correspondances)
if 'class="next' not in contenu:
print("Dernière page atteinte.")
break
indice_page += 1
time.sleep(1)
print("\n" + "=" * 50)
print("RÉSULTATS")
print("=" * 50)
print("N°\tPrix\t\tArticle")
print("-" * 50)
for numero, (montant, designation) in enumerate(articles, start=1):
print(f"{numero}\t¥{montant}\t{designation.strip()}")
if __name__ == "__main__":
extraire_produits()
Points techniques
Le pré-test de connectivité évite les traitemants inutiles en cas d'indisponibilité du serveur. L'expression régulière exploite re.DOTALL pour capturer des motifs multilignes. La temporisation de une seconde entre requêtes respecte la politique de courtoisie du web scraping.
Exercice 3 : Téléchargement d'images depuis un portail universitaire
Ce programme parcourt six pages du site d'actualités de l'Université Fuzhou pour archiver les images au format .jpg, .jpeg ou .png.
Solution complète
import requests
from bs4 import BeautifulSoup
import os
import time
from urllib.parse import urljoin
urls_cibles = [
"https://news.fzu.edu.cn/yxfd.htm",
"https://news.fzu.edu.cn/yxfd/1.htm",
"https://news.fzu.edu.cn/yxfd/2.htm",
"https://news.fzu.edu.cn/yxfd/3.htm",
"https://news.fzu.edu.cn/yxfd/4.htm",
"https://news.fzu.edu.cn/yxfd/5.htm"
]
dossier_destination = "images_fzu"
compteur_images = 0
if not os.path.exists(dossier_destination):
os.makedirs(dossier_destination)
print(f"Dossier créé: {dossier_destination}")
def telecharger_image(url_image, numero_page):
global compteur_images
try:
entetes = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/128.0.0.0 Safari/537.36"
}
flux = requests.get(url_image, headers=entetes, timeout=15)
flux.raise_for_status()
nom_fichier = url_image.split("/")[-1]
if "." not in nom_fichier:
nom_fichier += ".jpg"
nom_final = f"page_{numero_page}_{compteur_images + 1}_{nom_fichier}"
chemin_sauvegarde = os.path.join(dossier_destination, nom_final)
with open(chemin_sauvegarde, "wb") as fichier:
fichier.write(flux.content)
compteur_images += 1
print(f"[Page {numero_page}] Téléchargée: {nom_final}")
return True
except Exception as erreur:
print(f"[Page {numero_page}] Échec: {url_image} — {erreur}")
return False
def analyser_page(url_page, numero_page):
print(f"\n--- Analyse page {numero_page}: {url_page} ---")
try:
entetes = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/128.0.0.0 Safari/537.36"
}
reponse = requests.get(url_page, headers=entetes, timeout=15)
reponse.encoding = reponse.apparent_encoding
soup = BeautifulSoup(reponse.text, "html.parser")
conteneurs = soup.find_all("div", class_="img slow")
if not conteneurs:
print(f"Aucune image repérée page {numero_page}")
return
for bloc in conteneurs:
balise_img = bloc.find("img")
if balise_img and balise_img.get("src"):
url_complete = urljoin(url_page, balise_img["src"])
telecharger_image(url_complete, numero_page)
time.sleep(1)
print(f"Page {numero_page} terminée")
except Exception as erreur:
print(f"Erreur page {numero_page}: {erreur}")
if __name__ == "__main__":
print("Démarrage du crawler d'images FZU")
for position, url in enumerate(urls_cibles):
page = position + 1
analyser_page(url, page)
if position < len(urls_cibles) - 1:
print("Pause de 2 secondes...")
time.sleep(2)
print(f"\nOpération terminée: {compteur_images} images archivées")
print(f"Emplacement: {os.path.abspath(dossier_destination)}")
Architecture du script
La fonction urljoin résout les chemins relatifs en URLs absolues, indispensable pour le téléchargement. La classe CSS img slow sert d'ancre sémantique pour localsier les conteneurs d'images. Le stockage en mode binaire ("wb") préserve l'intégrité des fichiers graphiques. Les temporisations escaladées (1 seconde entre images, 2 secondes entre pages) minimisent l'empreinte du crawler.