Web scraping notes allociné

Messages postés
2
Date d'inscription
mardi 29 octobre 2019
Statut
Membre
Dernière intervention
30 octobre 2019
-
Bonjour à tous,

J'essaye actuellement de créer un petit programme me permettant de scrap les notes presses de films sur Allociné (à partir de l'URL "http://www.allocine.fr/films/?page=" qui classe les films les films du plus populaire au moins populaire), cependant j'ai un problème au moment du développement de la boucle me permettant de récupérer toutes les notes d'une même page (afin de les regrouper dans un DataFrame).

Voilà le code :

token = 'http://www.allocine.fr/films/?page='
def get_pages(token, nb):
pages = []
for i in range(1,nb+1):
j = token + str(i)
pages.append(j)
return pages
pages = get_pages(token,1)

import requests
for i in pages:
response = requests.get(i)

response.text
response.headers

import bs4
soup = bs4.BeautifulSoup(response.text, 'html.parser')

em_box = soup.find_all("span", {"class":"stareval-note"})


import pandas as pd
parameters = ["Presse"]
df_f = pd.DataFrame()
for par in parameters:
l = []
for el in em_box:
j = el[par]
l.append(j)
l = pd.DataFrame(l, columns = [par])
df_f = pd.concat([df_f,l], axis = 1)



C'est au niveau de cette ligne "parameters = ["Presse"]" que le problème se situe, je reçois sans cesse une "key error" quand je lance la boucle, je ne sais pas quoi mettre dans ma liste parameters.
Pourtant, lorsque je lance ma variable em_box, par exemple "em_box[0]" je tombe sur la note presse du premier film de la page (à savoir le 4/5 du Joker).
Je suis débutant en Python et je ne parviens pas bien à lire l'HTML de l'URL que j'utilise, j'ai réussi à cibler les balises qui m'intéressaient (span, class:stareval note) mais c'est donc sur la généralisation du process que en une seule boucle que ça pose problème.

Merci d'avance pour votre aide.
Afficher la suite 

2 réponses

0
Merci
Bonjour,

Ton problème n'est pas clair.
Je suppose que l'erreur est ici ?
for el in em_box:
    j = el[par]


Je dirais que oui, car selon la doc de bs4, el est une instance de Tag, qui n'a donc pas d'item par...
En revanche il y a une propriété text,
print(em_box[0].text
. Est-ce que c'est ça que tu veux obtenir ?
Commenter la réponse de khrug
Messages postés
2
Date d'inscription
mardi 29 octobre 2019
Statut
Membre
Dernière intervention
30 octobre 2019
0
Merci
Bonjour,

Tout d'abord merci pour vos réponses. Je suis finalement parti sur complètement autre chose. Mon code a l'air de fonctionner cette fois-ci, cependant un problème très étrange subsiste.

Voici mon code :


from time import sleep
from random import randint
from IPython.core.display import clear_output
from time import time
import bs4
from bs4 import BeautifulSoup
import requests
from requests import get


pages = [str(i) for i in range(8,10)]

# Ici on crée d'emblée une liste avec les variables qui nous intéresse, ce sont des listes qui vont 
#être remplies au fur et à mesure 
noms_de_films = []
années_de_sortie = []
note_presse = []



# Tout ce qui est en rapport avec ce "time" nous permet de ne pas se faire prendre pour un robot 
# Par les "détecteurs" de IMDB, en instaurant volontairement ce temps de "pause" entre chaque recherche
# Sur les pages du site, on passe pour un utilisateur lambda. 
debut_temps = time()
requests = 0

for page in pages:

    # Avec cette fonction, on demande à notre variable reponse d'aller chercher 
    #Un URL qui va évoluer en même temps que url_années et pages (ainsi notre fonction va 
    #automatiquement défiler les années de sortie et les pages associées)
    #Le "&sort=num_votes,desc&page=" permet quant à lui de prendre la classification par notes décroissante
        reponse = get('http://www.allocine.fr/films/?page=' + page)

        # Ca c'est le temps de pause de notre boucle, entre chaque boucle (entre chaque page) la pause
        #durera entre 8 et 15 secondes (des entiers aléatoires)
        sleep(randint(2,8))

        # Cette partie du code est surtout un point d'appui nous permettant de savoir combien de reqûete nous
        #allons faire au site et les secondes qui s'écoulent entre chacune de ces requêtes. 
        requests += 1
        temps_ecoule = time() - debut_temps
        print('Request:{}; Frequency: {} requests/s'.format(requests, requests/temps_ecoule))
        clear_output(wait = True)

        # Ici il s'agit d'une lecture classique de l'HTML des pages de l'URL que l'on a mis en place avec 
        # La fonction reponse, le reponse.text permet de faire apparaître l'HTML de chaque page dans notre
        #console Python, permettant ainsi de trouver les balises HTML qui nous intéressent
        page_html = BeautifulSoup(reponse.text, 'html.parser')

        # C'est ici qu'on commence les recherches de balise, on peut remarquer dans le code HTML des pages 
        # IMDB (qui est beaucoup plus clair d'ailleurs que celles d'Allociné) que chaque film est 
        #Est associé à ces balises "lister-item mode_advanced", il y en a en tout et pour tout 50
        # Par page. L'outil "find_all" permet donc de trouver ces 50 films à chacun de nos tours de boucle
        # C'est à partir de là qu'on indente avec une boucle for, car on va aller chercher les informations
        #qui nous intéressent (nom du film, notes etc..) dans chacune de ces balises. 
        movies = page_html.find_all('li', class_ = 'mdl')

        # For every movie of these 50
        for movie in movies:
            # Cette condition nous permet de mettre de côté les films qui n'ont pas de métascore
            # Ainsi on s'assure de ne pas avoir de blancs deans notre tableau de résultat final. 
            if movie.find('span', class_ = 'stareval-note') is not None:
                

    # Je ne saurai pas donné de termes techniques pour expliquer cette méthode, mais on se sert de notre
    # "curseur" movie pour faire défiler le code html de la page scrapée, ainsi on lui dit que le nom du film
    # se trouve dans une balise text qui se trouve elle-même dans une balise a qui est dans une balise h3.
    # Ce résultat se vérifie aisément en lisant le code source d'une des pages du site.
    #Ensuite, chaque résultat trouvé vient s'ajouter à notre list implementée au départ. 
                nom_du_film = movie.h2.a.text
                noms_de_films.append(nom_du_film)

    # Ici l'idée est la même sauf que la fonction find nous permet de trouver la première inhérence 
    # de la balise "lister_item-year" (qui est ici celle qui nous interesse)
                année_de_sortie = movie.div.find('span', class_ = 'date').text
                années_de_sortie.append(année_de_sortie)

                # Pareil 
                presse = movie.find('span', class_ = 'stareval-note').text
                note_presse.append(presse)

import pandas as pd
test_df = pd.DataFrame({'movie': noms_de_films,'year': années_de_sortie,'note': note_presse})
print(test_df.info())
test_df            



En fait je réussis à effectuer une boucle qui scrap différentes infos sur chaque page allociné (le titre, la note presse et la date de sortie), cependant je reçois à intervalle régulier un message d'erreur de type "'NoneType' object has no attribute 'text" au niveau de la ligne "année_de_sortie = movie.div.find('span', class_ = 'date').text". Ce qui est bizarre c'est qu'aucune "logique" ne ressort de cette erreur puisque cette erreur surgit à la requête 9, la requête 17, la requête 23 (avec requête 9 = page 9 d'Allociné). Je ne sais donc pas si l'erreur vient de moi ou si c'est le codage HTML du site allociné qui pose problème, je n'ai cependant rien remarqué en vérifiant l'HTML des pages qui posent problème.

Pouvez-vous m'éclairer ?

Merci d'avance.
Bonjour,

Ce que j'en comprends est qu'il n'existe pas de span avec date comme class.

Si on regarde page 9, il y a :

Wounds
Date de sortie inconnue / 1h 36min /


Donc j'en déduirais que dans la source html, pour cet article y a pas de span pour la date, la flemme de chercher dans la source html.

Si c'est ça, bah tu peux gérer ça à ta sauce, condition ou exception afin de définir une valeur représentant "indéterminé" dans ton script, enfin c'est à toi de choisir ^^
Commenter la réponse de Son06