1
votes

la boucle for se répète en python

J'ai créé un robot Web qui itère sur un site Web, par exemple example.com/?id=int int est un entier. la fonction obtient le résultat en html brut à l'aide de la bibliothèque requests puis le transmet à parseAndWrite pour extraire un div et enregistrer sa valeur dans une base de données sqlite:

def archive(initial_index, final_index):
    while True:
        try:
            for i in range(initial_index, final_index):
                res = requests.get('https://www.example.com/?id='+str(i))
                parseAndWrite(res.text)
                print(i, ' archived')

        except requests.exceptions.ConnectionError:
            print("[-] Connection lost. ")
            continue
        except: 
            exit(1)
        break 

archive(1, 10000)

Mon problème est qu'après un certain temps, la boucle ne continue pas jusqu'à 10000 mais se répète à partir d'une valeur aléatoire, ce qui entraîne de nombreux enregistrements en double dans le base de données. Quelle est la cause de cette incohérence?


4 commentaires

À toute erreur de connexion, votre redémarrage à partir de 1.


@Daniel, ah! comment n'ai-je pas pu remarquer ce problème stupide ...


Placez le try / except autour du corps de la boucle for plutôt qu'autour de la boucle entière. Ensuite, vous pouvez vous débarrasser de la boucle while True .


Sans rapport, mais vous devriez probablement laisser les autres exceptions se propager hors de votre fonction plutôt que de quitter immédiatement. Laisser celui qui a appelé archive décider quoi faire en cas d'erreur inattendue.


3 Réponses :


3
votes

Je pense que vos deux boucles sont imbriquées dans le mauvais ordre. La boucle externe while est censée réessayer toutes les URL qui causent des erreurs de connexion, mais vous l'avez placée en dehors de la boucle for les itérations sur les numéros d'URL. Cela signifie que vous commencez toujours à partir de l'index initial chaque fois qu'une erreur se produit.

Essayez de permuter les boucles, et vous ne répéterez qu'une seule URL jusqu'à ce que cela fonctionne:

def archive(initial_index, final_index):
    for i in range(initial_index, final_index):
        while True:
            try:
                res = requests.get('https://www.example.com/?id='+str(i))
                parseAndWrite(res.text)
                print(i, ' archived')

            except requests.exceptions.ConnectionError:
                print("[-] Connection lost. ")
                continue
            except: 
                exit(1)
            break 

archive(1, 10000)


0 commentaires

1
votes

Si une erreur de connexion se produit, vous redémarrez à initial_index . Au lieu de cela, vous pouvez réessayer l'index actuel encore et encore, jusqu'à ce que la connexion réussisse:

def archive(initial_index, final_index):
    for i in range(initial_index, final_index):
        while True:
            try:
                response = requests.get(f'https://www.example.com/?id={i}')
                parseAndWrite(response.text)
                print(f'{i} archived')
            except requests.exceptions.ConnectionError:
                print("[-] Connection lost. ")
            else:
                break 

archive(1, 10000)


0 commentaires

3
votes

Une règle générale pour une instruction try est d'exécuter le moins de code possible dans une instruction; ne mettez que le code que vous attendez produira l'erreur que vous voulez y détecter; tout autre code est placé avant ou après l'instruction.

N'attrapez pas les erreurs dont vous ne savez pas quoi faire. Quitter le programme est rarement la bonne chose à faire; cela se produira de toute façon si personne d'autre ne détecte l'exception, alors donnez à votre appelant la possibilité de la gérer.

Et enfin, ne construisez pas d'URL vous-même; laissez la bibliothèque requests faire cela pour vous. L'URL de base est http://www.example.com ; le paramètre id et sa valeur peuvent être passés via un dict à requests.get.

Votre boucle externe va itérer sur les différents paramètres utilisés pour construire l'URL; la boucle interne essaiera la demande jusqu'à ce qu'elle réussisse. Une fois la boucle interne terminée, vous pouvez utiliser la réponse pour appeler parseAndWrite.

def archive(initial_index, final_index):

    base_url = 'https://www.example.com/'
    for i in range(initial_index, final_index + 1):
        while True:
            try:
                res = requests.get(base_url, params={'id': i})
            except requests.exception.ConnectionError:
                print("[-] Connection lost, trying again")
                continue
            else:
                break
        parseAndWrite(res.text)
        print('{} archived'.format(i))

archived(1, 10000)

Vous pouvez également envisager de laisser requêtes code > gérez les tentatives pour vous. Voir Puis-je définir max_retries pour les demandes.request? pour commencer.


0 commentaires