Optimisation du script de scrapping et annotations de type
Bonsoir,
Je viens de terminer l'exercice, de la formation sur le scrapping, dans lequel il faut récupérer le nom des catégories qui dispose d'un nombre de livres inférieur à une quantité déterminée.
import requests
from bs4 import BeautifulSoup
response = requests.get(url="https://books.toscrape.com/")
with open("index.html", "w") as f:
f.write(response.text)
with open("index.html") as fp:
soup = BeautifulSoup(fp, "html.parser")
def book_category_labels() -> list:
categories = [element.string.strip() for element in soup.select(".side_categories .nav li ul li a")]
return categories
def book_category_urls() -> list:
categories = [element["href"] for element in soup.select(".side_categories .nav li ul li a")]
return categories
def detail_categories(category: str) -> str:
category_url = requests.get(url=f"{response.url}{category}")
with open("detail_category.html", "w") as f:
f.write(category_url.text)
with open("detail_category.html", "r") as f:
soup = BeautifulSoup(f, "html.parser")
return soup.find(name="form").find(name="strong").string
def results_by_book_category(criteria: int):
categories = book_category_labels()
urls = book_category_urls()
results = {categories[i]: detail_categories(category=urls[i]) for i in range(len(categories))}
for k, v in results.items():
if (int(v)) < criteria:
yield k
for element in results_by_book_category(criteria=20):
print(element)
Le résultat s'affiche 10-15 secondes après l'exécution du script. Je pense que la lenteur provient de l'écriture de l'html dans le fichier à chaque itération pour analyser le "strong". Par conséquent, je ne pense pas avoir trouvé la meilleure des façons de résoudre cet exercice. Ma question est la suivante : devrais-je chercher une meilleure solution pour cet exercice ? Sachant que le script est lent avec 50 catégories. Je n'imagine même pas avec des milliers...
Petite question subsidiaire : au niveau des annotations de type, je ne sais pas quoi mette à la fonction "results_by_book_category". Vu que le "yield" retourne un générateur, je ne vois pas quel annotation je peux mettre.
Merci et à bientôt.
Salut Edouard,
Effectivement, écrire chaque réponse HTML dans un fichier et les lire ensuite en boucle n’est pas la méthode la plus efficace !
Tu peux simplifier et accélérer ton code en manipulant directement les réponses HTML sans passer par des fichiers intermédiaires. Tu n'es en général pas du tout obligé de garder ces informations sur le disque. Je le montre dans la formation au début pour montrer que ça peut être pratique pour garder une trace ou si jamais tu veux analyser le HTML sans avoir besoin de faire de requêtes vers le site à chaque fois (pour éviter notamment sur des sites un peu critique de risquer un bannissement si tu n'utilises pas de réseau de proxy).
Du coup tu peux faire directement :
category_response = requests.get(url=category_full_url)
category_soup = BeautifulSoup(category_response.text, "html.parser")
Pour l’annotation de type avec yield, quand tu utilises un yield, tu retournes un itérateur. Dans ce cas, tu peux annoter results_by_book_category comme retournant Iterator[str] (à adapter en fonction du type de ce que tu retournes).
from typing import Iterator
def results_by_book_category(criteria: int) -> Iterator[str]:
# ... ton code ici ...
Tu verras également pour l'optimisation que ça va aller pas mal plus vite par la suite en utilisant les sessions du module requests ;)
Bonne continuation !
Bonjour Thibault,
Ok je vois. je prends note de ce retour pour avancer plus efficacement. Merci bien.
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte