для l oop повторяется в python - PullRequest
       5

для l oop повторяется в python

1 голос
/ 19 февраля 2020

Я создал веб-бота, который перебирает веб-сайт, например example.com/?id=int, где int - некоторое целое число. функция получает результат в формате html, используя библиотеку requests, затем передает его parseAndWrite, чтобы извлечь div и сохранить его значение в sqlite db:

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)

Моя проблема в том, что через некоторое время l oop не переходит на 10000, а повторяется из случайного значения, что приводит к появлению множества дублирующих записей в базе данных. Что вызывает это несоответствие?

Ответы [ 3 ]

3 голосов
/ 19 февраля 2020

Общее правило для оператора try - выполнять как можно меньше кода внутри него; только поместите код, который вы ожидаете, приведет к ошибке, которую вы хотите поймать в нем; весь другой код идет до или после оператора.

Не перехватывайте ошибки, с которыми вы не знаете, что делать. Выход из программы - редко правильная вещь; это произойдет в любом случае, если никто больше не поймает исключение, поэтому предоставьте вашему звонящему возможность обработать его.

И, наконец, не создавайте URL-адреса самостоятельно; пусть библиотека requests сделает это за вас. Базовый URL-адрес http://www.example.com; параметр id и его значение могут быть переданы через dict в requests.get.

Ваш внешний l oop будет перебирать различные параметры, используемые для построения URL; внутренний l oop будет пытаться выполнить запрос, пока он не будет выполнен успешно. Как только внутренний l oop завершается, вы можете использовать ответ для вызова 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)

Вы можете также рассмотреть возможность разрешения requests повторных попыток для вас. См. Могу ли я установить max_retries для request.request? для начала.

3 голосов
/ 19 февраля 2020

Я думаю, что ваши две петли вложены в неправильном порядке. Предполагается, что внешний while l oop повторяет любые URL-адреса, которые вызывают ошибки подключения, но вы поставили его вне for l oop, итерации по номерам URL-адресов. Это означает, что вы всегда начинаете с начального индекса при возникновении ошибки.

Попробуйте поменять местами циклы, и вы будете повторять только один URL, пока он не заработает:

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)
1 голос
/ 19 февраля 2020

Если возникает какая-либо ошибка соединения, вы перезагружаетесь с initial_index. Вместо этого вы можете повторять текущий индекс снова и снова, пока соединение не будет установлено успешно:

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)
...