Повторяющаяся ошибка HTTP 413 при очистке нескольких страниц

Я собираю сообщения с Wykop.pl («Польский Reddit»), просматривая несколько страниц, которые были возвращены, когда я искал на сайте интересующее меня ключевое слово. Я написал цикл для итерации моего целевого контента для каждой страницы; однако цикл завершается на определенных страницах (постоянно) с ошибкой «Ошибка HTTP 413: объект запроса слишком велик».

Я пытался очистить проблемные страницы по отдельности, но одно и то же сообщение об ошибке повторялось. Чтобы обойти это, мне пришлось установить свои диапазоны вручную для сбора данных, но за счет пропуска большого количества данных, и я хотел бы знать, есть ли решение Pythonic для решения этой ошибки. Я также пробовал более длительные паузы, так как, возможно, я рисковал отправить слишком много запросов, но, похоже, это не так.

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


from mtranslate import translate
posts = []
votes = []
dates = []
images = []
users = []

start_time = time()
requests = 0
pages = [str(i) for i in range(1,10)]

for page in pages:
    url = "https://www.wykop.pl/szukaj/wpisy/smog/strona/" + page + "/"
    response = get(url)

    # Pause the loop
    sleep(randint(8,15))

        # Monitor the requests
    requests += 1
    elapsed_time = time() - start_time
    print('Request:{}; Frequency: {} requests/s'.format(requests, requests/elapsed_time))
    clear_output(wait = True)
    # Throw a warning for non-200 status codes
    if response.status_code != 200:
        warn('Request: {}; Status code: {}'.format(requests, response.status_code))
    # Break the loop if the number of requests is greater than expected
    if requests > 10:
        warn('Number of requests was greater than expected.')
        break


    soup = BeautifulSoup(response.text, 'html.parser')
    results = soup.find_all('li', class_ = "entry iC")


    for result in results:
            # Error handling
            try:

                post = result.find('div', class_ = "text").text
                post = translate(post,'en','auto')
                posts.append(post)

                date = result.time['title']
                dates.append(date)

                vote = result.p.b.span.text
                vote = int(vote)
                votes.append(vote)

                user = result.div.b.text
                users.append(user)

                image = result.find('img',class_='block lazy')
                images.append(image)

            except AttributeError as e:
                print(e)

Если бы я мог запустить сценарий сразу, я бы установил диапазон от 1 до 163 (поскольку у меня есть 163 страницы результатов сообщений, в которых упоминается интересующее меня ключевое слово). Таким образом, мне пришлось установить меньшие диапазоны для постепенного сбора данных, но опять же за счет пропуска страниц данных.

Альтернативой, которую я использую на случай непредвиденных обстоятельств, является очистка от обозначенных проблемных страниц в виде загруженных html-документов на моем рабочем столе.

Отсутствует импорт BS4, друг! Возможно, вы просто ошиблись при оклейке.

Erick Guerra 09.04.2019 03:23

Также! утечка памяти — очень распространенная проблема с библиотекой запросов. Вместо этого вам следует изучить асинхронные запросы, чтобы справиться с этим. Еще лучше, начните использовать scrapy!

Erick Guerra 09.04.2019 03:31
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
360
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Возможно, вы натолкнулись на какое-то ограничение IP-адреса. При запуске скрипт у меня работает нормально без ограничения скорости (на данный момент). Тем не менее, я бы порекомендовал вам использовать requests.Session() (вам нужно изменить переменную requests, иначе она переопределит импорт). Это может помочь уменьшить возможные проблемы с утечкой памяти.

Так, например:

from bs4 import BeautifulSoup
from time import sleep
from time import time
from random import randint
import requests

posts = []
votes = []
dates = []
images = []
users = []

start_time = time()
request_count = 0
req_sess = requests.Session()

for page_num in range(1, 100):
    response = req_sess.get(f"https://www.wykop.pl/szukaj/wpisy/smog/strona/{page_num}/")

    # Pause the loop
    #sleep(randint(1,3))

    # Monitor the requests
    request_count += 1
    elapsed_time = time() - start_time
    print('Page {}; Request:{}; Frequency: {} requests/s'.format(page_num, request_count, request_count/elapsed_time))
    
    #clear_output(wait = True)
    # Throw a warning for non-200 status codes
    if response.status_code != 200:
        print('Request: {}; Status code: {}'.format(requests, response.status_code))
        print(response.headers)
    
    # Break the loop if the number of requests is greater than expected
    #if requests > 10:
    #    print('Number of requests was greater than expected.')
    #    break

    soup = BeautifulSoup(response.text, 'html.parser')
    results = soup.find_all('li', class_ = "entry iC")

    for result in results:
        # Error handling
        try:
            post = result.find('div', class_ = "text").text
            #post = translate(post,'en','auto')
            posts.append(post)

            date = result.time['title']
            dates.append(date)

            vote = result.p.b.span.text
            vote = int(vote)
            votes.append(vote)

            user = result.div.b.text
            users.append(user)

            image = result.find('img',class_='block lazy')
            images.append(image)

        except AttributeError as e:
            print(e)
            

Дал следующий вывод:

Page 1; Request:1; Frequency: 1.246137372973911 requests/s
Page 2; Request:2; Frequency: 1.3021880233774552 requests/s
Page 3; Request:3; Frequency: 1.2663757427416629 requests/s
Page 4; Request:4; Frequency: 1.1807827876080845 requests/s                
.
.
.
Page 96; Request:96; Frequency: 0.8888853607003809 requests/s
Page 97; Request:97; Frequency: 0.8891876183362001 requests/s
Page 98; Request:98; Frequency: 0.888801819672809 requests/s
Page 99; Request:99; Frequency: 0.8900784741536467 requests/s                

Это также отлично работало, когда я начинал с гораздо большего количества страниц. Теоретически, когда вы получаете код состояния ошибки 413, теперь он должен отображать заголовки ответа. Согласно RFC 7231, сервер должен возвращать поле заголовка Retry-After, которое вы можете использовать, чтобы определить, как долго ждать до вашего следующего запроса.

Привет Мартин; работал как шарм! Вот что интересно: я думаю, что это был модуль перевода ('post = translate(post,'en','auto')'), который сбрасывал весь скрипт. Я попробовал ваш скрипт с отключенным и активным переводом, я предполагал, что последний замедлит процесс очистки, но нет! Он вернул ту же ошибку 413 на странице 13. Похоже, в этом и была суть проблемы.

HP-Nunes 09.04.2019 19:28

Итак, вот загвоздка:

Ошибка 413 связана не с Wykop, веб-сайтом, подлежащим очистке, а с пакетом mtranslate, который использует API Google Translate. В моем исходном коде произошло то, что когда Wykop был очищен, он затем перевел сообщения с польского на английский. Однако Google Translation API имеет ограничение примерно в 100 000 символов за 100 секунд на пользователя. Поэтому, когда код достиг 13-й страницы, mtranslate достиг лимита запросов для переводчик Google. Следовательно, решение Мартина отлично работает при очистке данных с отключенной функцией перевода.

Я пришел к такому выводу, когда использовал модуль для перевода сообщений, хранящихся в фрейме данных, так как я столкнулся с той же ошибкой примерно на отметке 8% моего цикла перевода.

Другие вопросы по теме

Умножение определенных ячеек, перечисленных по индексу строки в столбце фрейма данных, на константу
Как правильно идентифицировать значения с плавающей запятой [0, 1], содержащие точку, в типе объекта DataFrame?
Пытаюсь получить расстояние, используя долготу и широту, но продолжаю работать с ошибкой: объект «Серия» не имеет атрибута «радианы»
Найдите процент от общего количества категорий, отсортируйте от самой высокой до самой низкой, сохраните имена первых 80% и переименуйте все остальные в «другие»
Изменить значение элемента с учетом флага
Добавление наблюдений с одинаковым столбцом и создание одной уникальной строки для каждого наблюдения
Как масштабировать массив numpy от 0 до 1 с перерегулированием?
Сравнение сжатого распределения по когортам
Импорт нескольких файлов Excel в несколько pd.Series
Слияние или объединение сотен файлов Excel