Scraping annuaire

Bonjour,

Je poursuis mon avancée dans mon projet de scrap python. J'en suis à la ligne 25. J'ai cette erreur :

IndentationError: expected an indented block after 'for' statement on line 24.

import re

import pages
import requests

from bs4 import BeautifulSoup
def get_html(url):
    r = requests.get(url)=+
    soup = BeautifulSoup(r.content, "html.parser")
    return soup

def get_urls(html):
    notaire_items = html.find_all("div", {"class": "node__content clearfix"})
    print(len(notaire_items))


def get_all():
    page_number


del get_all():
    page_number = 0

for i in range(51):
    i = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
    page_number += 1
    print(i)

    






def main():
        url = "https://www.notaireetbreton.bzh/annuaire-notaire?page=0"
        html = get_html(url)
        get_urls(html)
main()











L'idée, c'est d'afficher les 51 pages de l'URL concernée :

https://www.notaireetbreton.bzh/annuaire-notaire?page=0


“Impose ta chance, serre ton bonheur et va vers ton risque. A te regarder, ils s’habitueront.”  René Char 

9 réponses

Résumé de la discussion

Le problème central porte sur un projet de scraping Python visant un annuaire de notaires et sur des erreurs d’Indentation et de syntaxe lors de l’affichage des 51 pages. La meilleure réponse propose une version robuste: structurer le code en fonctions et générer les URLs des pages dans une boucle pour itérer sur 51 pages et extraire les informations. D’autres contributions soulignent des lacunes en Python et proposent d’abord récupérer la première page avec des méthodes simples, d’évoquer les erreurs de syntaxe et l’environnement virtuel. En fin de compte, l’approche recommandée met l’accent sur la modularité, la boucle d’itération et la robustesse, tout en anticipant les chemins d’écriture du fichier.

Bobot (l’IA à votre service)
  1. Bon, erreur d'indentation, il fallait aligner la ligne 25 sur le "IN"de la ligne 24.

    Je continue. A plus tard :)


    0
    1. Dans ta boucle ligne 24, la variable i passe de 0 à 50

      et tu l'écrase ensuite avec une chaine de caractères

      Ca marche, mais ce serait plus sympa comme ça:

      for _ in range(51):
          page = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
          page_number += 1
          print(page)
      0
      1. Contributeur

        Je ferais plutôt ainsi:

        for page_number in range(51):
            page = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
            print(page)
        0
      2. Si je fais comme toi, jai :

          File "C:\Users\quent\PycharmProjects\pythonProject\scraping\TESTS.py", line 9, in get_urls

            notaire_items = html.find_all("div", {"class": "node__content clearfix"})

        AttributeError: 'NoneType' object has no attribute 'find_all'

        Ça marche, j'ai les 51 pages. Dans mon essai aussi ! Merci !

        0
    2. import re
      
      import pages
      import requests
      
      from bs4 import BeautifulSoup
      from werkzeug import urls
      
      
      def get_urls(html):
          notaire_items = html.find_all("div", {"class": "node__content clearfix"})
          print(len(notaire_items))
      
      def get_all(pages):
          urls []
          page_number = 0
      
          for i in range(51):
              i = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
              page_number += 1
              urls.append(i)
          print(urls)
      
          return urls
      
          
      
      
      
      
      
      
      def main():
              url = "https://www.notaireetbreton.bzh/annuaire-notaire?page=0"
              html = get_all(url)
              get_urls(html)
      main()
      
      
      
      
      
      
      
      
      
      
      
      

      J'ai créé une liste urls: "urls [ ]" en ligne 15, j'ai cette erreur :

      SyntaxError: invalid syntax

      Enfin le prof fait comme cela ! lol

      En ligne 11, il a utilisé la class "h2", je ne sais pas s'il y a un lien de cause à effet ?


      0
      1. urls = []
        0
      2. @Diablo76

        Merci !

        0
    3. mais tes lignes de 18 à 21 sont toujours aussi vilaines ...

      il y a le fonctionnement d'un code, mais aussi son élégance

      c'est vrai qu'on peut toujours écrire un plat de nouilles qui marche :-)

      0
      1. import re
        
        import pages
        import requests
        
        from bs4 import BeautifulSoup
        
        
        
        def get_urls(html):
            notaire_items = html.find_all("div", {"class": "node__content clearfix"})
            print(len(notaire_items))
        
        def get_all(pages):
            urls = []
            page_number = 0
        
            for i in range(51):
                i = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
                page_number += 1
                urls.append(i)
        
            return urls
        
        def parse_notary():
            r = requests.get("https://www.notaireetbreton.bzh/annuaire-notaire?page")
            soup = BeautifulSoup(r.content, "html.parser")
        
            notary = soup.find_all ('div' , class_='data-history-node-id="15687"role="article')
            print(len (notary))
        
            for notaire in notaires:
               try:
                   nom = notaire.find("node__content clearfix").text.strip()
               except AttributeError as e:
                   nom = ""
               try:
                   adresse = notaire.find('span', class_='adresse').text.strip()
               except AttributeError as e:
                   adresse = ""
               try:
                   adresse_finale = re.sub(r"\s+", " ", adresse)
               except AttributeError as e:
                   adresse_finale = ""
               try:
                   telephone = notaire.find('span', class_='telephone').text.strip()
               except AttributeError as e:
                   telephone = ""
               try:
                   email = notaire.find('span', class_='email').a.text.strip()
               except AttributeError as e:
                   email = ""
        
                   chemin = r"C:\Users\quent\PycharmProjects\pythonProject\ANNUAIRE-NOTAIRE.txt"
                   with open(chemin, "a") as f:
                       f.write(f"{nom}\n")
                       f.write(f"{adresse_finale}\n")
                       f.write(f"{telephone}\n")
                       f.write(f"{email}\n")
        
        
        def parse_all_notary():
            pages = get_all_pages()
            for page in pages:
                parse_notary(page)
                print(f"On scrape {page}")
        
        parse_all_notary()
        
        
        
        
        
        
            
        
        
        
        
        
        
        def main():
                url = "https://www.notaireetbreton.bzh/annuaire-notaire?page=0"
                html = get_all(url)
                get_urls(html)
        main()
        
        
        
        
        
        
        
        
        
        
        
        

        Erreur ligne 63 :

          File "C:\Users\quent\PycharmProjects\pythonProject\scraping\TESTS.py", line 68, in <module>

            pages = get_all_pages()

        NameError: name 'get_all_pages' is not defined

        0
      2. @quentin2121

        il suffit de lire

        la fonction ne s'appelle pas get_all_pages()

        mais get_all(pages)

        0
      3. @Phil_1857

        Fait comme tu as dit :

          File "C:\Users\quent\PycharmProjects\pythonProject\scraping\TESTS.py", line 68, in <module>

          File "C:\Users\quent\PycharmProjects\pythonProject\scraping\TESTS.py", line 63, in parse_all_notary

            pages = get_all(pages)

        UnboundLocalError: cannot access local variable 'pages' where it is not associated with a value

        Comment attribuer une valeur à une variable ?

        0
    4. Salut, la question à se poser est quel est l'intérêt de créer une liste d'url ?

      À la limite, on pourrait créer un générateur afin d'éviter ce stockage à usage unique.

      def get_urls(page_number):
          for page in range(page_number):
              yield 'https://www.notaireetbreton.bzh/annuaire-notaire?page=%25d' % page
      
      
      for url in get_urls(50):
          print(url)

      Mais même là, l'intérêt est nul.

      Nb: évidemment il faut remplacer %25d par %d dans l'url...

      0
      1. Tu continues à copier-coller des bouts de code sans les comprendre pour les adapter à ton script...

        0
        1. Salut 

          J'ai fait un rajout au message 10.

          Et surtout, je n'ai pas marqué en RESOLU le sujet.

          Dommage de laissé tomber si près du but, je n'ai pas fait de copier coller bêtement comme l'autre jour, j'ai suivi au pas par pas les fonctions !

          0
        2. @quentin2121

          Je ne sais pas qui a marqué le sujet en RESOLU, mais ce que je sais, c'est que tu es très loin du but.

          Déjà au lieu de te compliquer les choses à vouloir scrapper les 51 pages, essaye déjà de récupérer les infos (Nom, Tel, etc...) de la première étude :

          0
        3. @Diablo76
          import re
          
          import pages
          import requests
          
          from bs4 import BeautifulSoup
          
          
          
          def get_urls(html):
              notaire_items = html.find_all("div", {"class": "node__content clearfix"})
              print(len(notaire_items))
          
          def get_all(pages):
              urls = []
              page_number = 0
          
              for i in range(51):
                  i = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
                  page_number += 1
                  urls.append(i)
          
              return urls
          
          def parse_notary():
              r = requests.get("https://www.notaireetbreton.bzh/annuaire-notaire?page")
              soup = BeautifulSoup(r.content, "html.parser")
          
              notary = soup.find_all ('div' , class_='data-history-node-id="15687"role="article')
              print(len (notary))
          
              for notary in notary:
                  try:
                     nom = notaire.find("node__content clearfix").text.strip()
                  except AttributeError as e:
                     nom = ""
                  try:
                     adresse = notaire.find('span', class_='adresse').text.strip()
                  except AttributeError as e:
                     adresse = ""
                  try:
                     adresse_finale = re.sub(r"\s+", " ", adresse)
                  except AttributeError as e:
                     adresse_finale = ""
                  try:
                     telephone = notaire.find('span', class_='telephone').text.strip()
                  except AttributeError as e:
                     telephone = ""
                  try:
                     email = notaire.find('span', class_='email').a.text.strip()
                  except AttributeError as e:
                     email = ""
          
                     chemin = r"C:\Users\quent\PycharmProjects\pythonProject\scraping\TESTS.txt"
                     with open(chemin, "a") as f:
                         f.write(f"{nom}\n")
                         f.write(f"{adresse_finale}\n")
                         f.write(f"{telephone}\n")
                         f.write(f"{email}\n\n")
          
          def parse_all_notarys(page=None):
              pages = get_all(page)
              for page in pages:
                  parse_notary()
                  print(f"On scrape {page}")
          
          parse_all_notarys()
          
          
          
          
          
          
              
          
          
          
          
          
          
          def main():
                  url = "https://www.notaireetbreton.bzh/annuaire-notaire?page=0"
                  html = get_all(url)
                  get_urls(html)
          main()
          input()
          
          
          
          
          
          
          
          
          
          
          

          Là ça fonctionne, sauf que le document .txt ne se trouve pas dans mon répertoire donné en ligne 54 ? Il ne se génère pas en fait ! Le prof a dit de se mettre en environnement virtuel pour ce projet.

          0
        4. @quentin2121

          Je ne sais pas si la balise commune à tous les notaires est la suivante :

          "node node-15523 node--type-office node--promoted node--view-mode-teaser clearxfix")
          

          Pour ce site : https://www.notaireetbreton.bzh/annuaire-notaire?page=0

          D'où l'impression du fichier texte qui ne s'effectue pas.

          0
        5. @quentin2121

          Bonsoir,

          Qu'est-ce qui ne te plaît pas dans ce que je t'ai montré comme code ?

          https://forums.commentcamarche.net/forum/affich-38050742-code-python-qui-ne-s-imprime-pas#61

          Je t'avais pourtant indiqué que dans les pages listant les notaires, il n'y avait ni téléphone ni courriel, puis cela se voit à 'affichage, non ?

          Pourquoi n'utilise-tu pas un fichier csv qui est parfaitement adapté à ce type de données ?

          Cesse le copié-collé et repars d'une base saine, parce là rien n'a changé par rapport au code que tu avais montré dans ton précédent sujet.

          Un prof ? Il sort d'où ton prof ? Parce que là, à te laisser patauger comme ça dans la mélasse, il a l'air un peu sadique ton prof  :-/ j'espère que tu ne débourses rien pour un service si médiocre :-S

           

          0
      2. Tu n'as (encore) les connaissances suffisantes en Python pour ce genre de projet, mais ça, on te l'a déjà dit.

        Avant que tu ne te décourages, voilà comment j'ai procédé (pour la première page) :

        import re
        import requests
        from bs4 import BeautifulSoup
        
        BASE_URL = "https://www.notaireetbreton.bzh"
        
        def get_soup(url):
            r = requests.get(url)
            soup = BeautifulSoup(r.content, "html.parser")
            return soup
        
        def get_notary_informations(notary_url):
            soup = get_soup(notary_url) 
            notary_name = soup.find("span", {"class": "field--name-title"}).text.strip()
            notary_phone = soup.find("div", {"class": "field--name-field-phone"}).text
            partial_contact_url = soup.find("a", {"class": "use-ajax"})['href']
            notary_mail  = get_notary_mail(partial_contact_url)
            notary_address = soup.find("div", {"class": "address"}).text
            notary_address = re.sub(r"[\s\n\t]+", " ", notary_address).strip()
            return (notary_name, notary_phone, notary_mail, notary_address)
        
        def get_notary_mail(partial_contact_url):
            soup = get_soup(BASE_URL + partial_contact_url)
            email_notary = soup.find("input", {"data-drupal-selector": "edit-email-to"}).get("value")
            return email_notary
        
        def show_informations(informations):
            for info in informations:
                print(info)
            print("")
        
        def main():
            url = f"{BASE_URL}/annuaire-notaire?page=0"
            soup = get_soup(url)
            notaries_item = soup.find_all("div", {"class": "node__content clearfix"})
            for notary_item in notaries_item:
                partial_notary_url = notary_item.find("a", href=True)
                notary_url = BASE_URL + partial_notary_url["href"]
                informations = get_notary_informations(notary_url)
                show_informations(informations)
        main()

        À toi d'analyser, de tracer ce script et pourquoi pas de le modifier pour ajouter la boucle qui te permettra d'obtenir les 51 pages.

        0
        1. Merci bien, tu es vraiment sympa de m'encourager ainsi !

          0
        2. import re
          import pages
          import requests
          from bs4 import BeautifulSoup
          
          BASE_URL = "https://www.notaireetbreton.bzh"
          
          
          def get_soup(url):
              r = requests.get(url)
              soup = BeautifulSoup(r.content, "html.parser")
              return soup
          
          
          def get_notary_informations(notary_url):
              soup = get_soup(notary_url)
              notary_name = soup.find("span", {"class": "field--name-title"}).text.strip()
              notary_phone = soup.find("div", {"class": "field--name-field-phone"}).text
              partial_contact_url = soup.find("a", {"class": "use-ajax"})['href']
              notary_mail = get_notary_mail(partial_contact_url)
              notary_address = soup.find("div", {"class": "address"}).text
              notary_address = re.sub(r"[\s\n\t]+", " ", notary_address).strip()
              return (notary_name, notary_phone, notary_mail, notary_address)
          
          
          def get_notary_mail(partial_contact_url):
              soup = get_soup(BASE_URL + partial_contact_url)
              email_notary = soup.find("input", {"data-drupal-selector": "edit-email-to"}).get("value")
              return email_notary
          
          
          def show_informations(informations, partial_contact_url=None, notary=None):
              for info in informations:
                  print(info)
              print(notary)
          
              for notary in notary:
                  try:
                      nom = notary.find("span", {"class": "field--name-title"}).text.strip()
                  except AttributeError as e:
                      nom = ""
                  try:
                      adresse = notary.find('span', class_='adresse').text.strip()
                  except AttributeError as e:
                      adresse = ""
                  try:
                      adresse_finale = re.sub(r"[\s\n\t]+", " ", notary_address).strip()
                  except AttributeError as e:
                      adresse_finale = ""
                  try:
                      telephone = notary.find("div", {"class": "field--name-field-phone"}).text
                  except AttributeError as e:
                      telephone = ""
                      try:
                          notary_mail = get_notary_mail(partial_contact_url)
                      except AttributeError as e:
                          email = ""
          
                          chemin = r"C:\Users\quent\PycharmProjects\pythonProject\scraping\NOTAIRES_ETUDESBRETONNES.txt"
                          with open(chemin, "a") as f:
                              f.write(f"{nom}\n")
                              f.write(f"{adresse_finale}\n")
                              f.write(f"{telephone}\n")
                              f.write(f"{email}\n\n")
          
          
          def main():
              url = f"{BASE_URL}/annuaire-notaire?page=0"
              soup = get_soup(url)
              notaries_item = soup.find_all("div", {"class": "node__content clearfix"})
              for notary_item in notaries_item:
                  partial_notary_url = notary_item.find("a", href=True)
                  notary_url = BASE_URL + partial_notary_url["href"]
                  informations = get_notary_informations(notary_url)
                  show_informations(informations)
          
          
          main()
          

            File "C:\Users\quent\PycharmProjects\pythonProject\scraping\NOTAIRES_ETUDES BRETONNES.py", line 37, in show_informations

              for notary in notary:

          TypeError: 'NoneType' object is not iterable

          Que faire lorsqu'un objet int n'est pas itérable  ?

          "Pour corriger cette erreur, vous pouvez utiliser une boucle while ou convertir l'objet entier en un autre type de données itérable , tel qu'une liste ou une chaîne. Vous pouvez également utiliser la fonction range() pour obtenir une plage de nombres et utiliser une boucle for pour parcourir cette plage."

          J'ai compris le souci, mais je sèche pour le corriger !

          Et pour la boucle for, pour toutes afficher les pages, je sais qu'il faut mettre une URL dynamique, mais je suis perdu pour le faire.

          En fait cela s'affiche, malgré l'erreur, mais seulement un notaire, comment terminer ma bouche for, pour tous les notaires ?

          0
        3. @quentin2121

          Mais pourquoi vouloir re-scrapper les infos avec ta boucle :

          for notary in notary:

          qui ne ressemble à rien, alors que ces infos existent déjà, car récupérés par la fonction 

          get_notary_informations()

          Code :

          def show_informations(informations):
              chemin = r"C:\Users\quent\PycharmProjects\pythonProject\scraping\NOTAIRES_ETUDESBRETONNES.txt"
              with open(chemin, "a") as f:
                  for info in informations:
                      f.write(f"{info}\n")
                  f.write("\n\n")

          Maintenant, tu n'as plus qu'à renommer cette fonction et son appel en save_informations c'est plus explicite.

          0
        4. @Diablo76
          def (save_informations (informations)):
              chemin = r"C:\Users\quent\PycharmProjects\pythonProject\scraping\NOTAIRES_ETUDESBRETONNES.txt"
              with open(chemin, "a") as f:
                  for info in informations:
                      f.write(f"{info}\n")
                      f.write("\n\n")
          
            File "C:\Users\quent\PycharmProjects\pythonProject\scraping\NOTAIRES_ETUDES BRETONNES.py", line 41
              def (save_informations (informations)):
          SyntaxError: invalid syntax
          

          J'ai mal renommé l'appel de (informations): ?

          0
        5. @quentin2121

          Non ,  la fonction :

          def save_informations(informations):

          Et pourquoi tu me décales :

          f.write("\n\n")

          ??? il te suffisait de copier/coller.

          0
      3. J'abandonne, il faut que je consulte, j'suis au bord de la dépression !!!!

        0
        1. C'est de l'humour noir, ou tu es sérieux ? J'y suis presque, je sais cela fait 10 jours que je dis ça. :)

          Ta façon de faire est bonne, différente du coach, mais ne dis t'on pas que tout les chemins mène à Rome. 

          0
      4. Bonsoir, non mais, mets toi à sa place, il te fournit un code fonctionnel récupérant ce qu'il faut dans la première page.

        Tout ce que tu as à faire est de mettre les parties concernées dans une simple boucle for, ce que tu es incapable de faire alors que c'est p... de simple.

        Bref, énième redite : tu ne comprends rien à ce que tu fais... la programmation c'est aussi être logique, mais comme tu n'as pas l'expérience nécessaire, tu ne peux avoir cette logique...

        Cf .
        Tu n'as (encore) les connaissances suffisantes en Python pour ce genre de projet, mais ça, on te l'a déjà dit.

        Il serait quand même grand temps de partir suivre un tuto apprenant les bases.

        0
        1. Non, la boucle in range, il faut l'intégrer à la fonction main(), mais pour ça, il faut gérer l'indentation et intégrer la variable dans l'URL du site.

          Désolé, tu as raison, je ne comprends pas. Je me suis dit, je mets la boucle in range à la suite de main(), comme je ne sais pas faire, je n'ai pas voulu aller plus loin et saloper le code à Diablo.

          Gérer l'indentation, je vois ce que c'est, intégrer la variable dans l'URL, là, je

          sèche. Est-ce cela :

          for i in range(51):
                  i = f"https://www.notaireetbreton.bzh/annuaire-notaire?page=%7Bpage_number%7D"
                  page_number += 1
                  urls.append(i)
          0
        2. @quentin2121

          salut.

          range en python :
          https://duckduckgo.com/?q=python+la+classe+range&t=ffab&ia=web%2A


          Différentes façons de formater une chaîne en python :
          https://duckduckgo.com/?q=python+diff%C3%A9rentes+fa%C3%A7ons+de+formater+une+cha%C3%AEne&t=ffab&ia=web

          Tu peux aussi ouvrir un interpréteur python et te servir de help.

          help(range)
          help('FORMATTING')


          Et même lancer une documentation de tous les modules dans ton navigateur (à taper dans ta console dos) :
           

          python -m pydoc -b
          0
        3. @bruf

          Bonjour,

          Merci pour ces infos.
          Si j'ai bien compris la fonction Range, je peux faire ainsi pour mon projet :
          
          
          a = 51
          for range i in range(a):
            print(i)
          Cela m'affichera mes 50 pages de l'annuaire(de la page 0 à la page 50) ?
          
          0
        4. @quentin2121

          Salut Diablo !

          Ton morceau de code en Message 23, il faut le copier où ? Si je le mets à suivre ton code, il donne un code zéro sans aucun affichage de texte dans la sortie console ? Si je le supprime, cela imprime bien la page 1 de l'annuaire ? Tu peux me montrer la totalité du code, au lieu de me faire me creuser les méninges, je le fais de toute façon, j'essaie de comprendre. Merci !

          0