1
votes

Impossible de forcer un script à essayer plusieurs fois lorsqu'il ne parvient pas à récupérer le titre d'une page Web

J'ai créé un script pour obtenir le titre de différentes boutiques à partir de pages Web identiques. Le script fonctionne bien.

J'essaie maintenant de créer une logique dans le script pour le laisser essayer plusieurs fois s'il ne parvient pas à récupérer les titres de ces pages.

À titre de test, si je définis la ligne avec selector autrement, comme dans name = soup.select_one (". sales-info> h"). text , le script ira en boucle indéfiniment.

J'ai essayé jusqu'à présent avec:

import requests
from bs4 import BeautifulSoup

links = (
    'https://www.yellowpages.com/san-francisco-ca/mip/nizarios-pizza-481135933',
    'https://www.yellowpages.com/nationwide/mip/credo-452182701'
)

def get_title(s,link):
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml")
    try:
        name = soup.select_one(".sales-info > h1").text
    except Exception:
        print("trying again")
        return get_title(s,link) #I wish to bring about any change here to let the script try few times other than trying indefinitely

    return name

if __name__ == '__main__':
    with requests.Session() as s:
        s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'
        for link in links:
            print(get_title(s,link))

Comment puis-je laisser le script essayer plusieurs fois lorsqu'il ne parvient pas à récupérer le titre d'une page Web?

PS Les pages Web que j'ai utilisées dans le script sont des espaces réservés.


0 commentaires

4 Réponses :


0
votes

Je pense que le moyen le plus simple serait de passer de la récursion à une boucle:

def get_title(s,link):
    failed = 0
    while failed < 5:
        try:
            r = s.get(link)
            soup = BeautifulSoup(r.text,"lxml")
            name = soup.select_one(".sales-info > h1").text
            return name
        except Exception: # Best to specify which one, by the way
            failed += 1
    print('Failed too many times')
    return None


0 commentaires

1
votes

J'ai ajouté des paramètres pour spécifier le nombre de tentatives, la mise en veille entre les tentatives et la valeur par défaut à renvoyer si tout échoue:

Retry 1/3
Retry 2/3
Retry 3/3
Failed to grab https://www.webscraper.io/test-sites/e-commerce/allinone
Retry 1/3
Retry 2/3
Retry 3/3
Failed to grab https://www.webscraper.io/test-sites/e-commerce/static

Impressions:

import time
import requests
from bs4 import BeautifulSoup


links = (
    'https://www.webscraper.io/test-sites/e-commerce/allinone',
    'https://www.webscraper.io/test-sites/e-commerce/static'
)

def get_title(s, link, retries=3, sleep=1, default=''):
    """
        s       -> session
        link    -> url
        retries -> number of retries before return default value
        sleep   -> sleep between tries (in seconds)
        default -> default value to return if every retry fails
    """

    name, current_retry = default, 0
    while current_retry != retries:
        r = s.get(link)
        soup = BeautifulSoup(r.text,"lxml")
        try:
            name = soup.select_one("h8").text
        except Exception:
            print("Retry {}/{}".format(current_retry + 1, retries))
            time.sleep(sleep)
            current_retry += 1

    return name

if __name__ == '__main__':
    with requests.Session() as s:
        s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'
        for link in links:
            print(get_title(s, link, 3, 1, 'Failed to grab {}'.format(link)))


0 commentaires

0
votes

Vous pouvez réaliser la même chose de différentes manières. En voici une autre que vous voudrez peut-être essayer:

import time
import requests
from bs4 import BeautifulSoup

links = [
    "https://www.yellowpages.com/san-francisco-ca/mip/nizarios-pizza-481135933",
    "https://www.yellowpages.com/nationwide/mip/credo-452182701"
]

def get_title(s,link,counter=0):
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml")
    try:
        name = soup.select_one(".sales-info > h").text
    except Exception:
        if counter<=3:
            time.sleep(1)
            print("done trying {} times".format(counter))
            counter += 1
            return get_title(s,link,counter)
        else:
            return None

    return name

if __name__ == '__main__':
    with requests.Session() as s:
        s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'
        for link in links:
            print(get_title(s,link))


0 commentaires

0
votes

Vous pouvez essayer d'utiliser n'importe quelle bibliothèque de nouvelle tentative, telle que ténacité , backoff . Notez que ces bibliothèques fonctionnent généralement comme des décorateurs et que votre fonction devra simplement effectuez l'importation, puis appelez le décorateur de la même manière que:

import requests
from bs4 import BeautifulSoup
from tenacity import retry ###or import backoff

...

@retry ###or @backoff.on_exception(backoff.expo, requests.exceptions.RequestException)
def get_title(s, link, retries=3, sleep=1, default=''):
...


0 commentaires