Каков наилучший способ оптимизировать этот цикл for для скорости? (pandas, объекты BS.)

#python #pandas #beautifulsoup

#python #pandas #beautifulsoup

Вопрос:

У меня есть фрейм / серия данных pandas с URL-адресом в каждой строке для создания красивого объекта Soup и извлечения данных изнутри. Однако цикл выполняется чрезвычайно медленно, и выполнение моего текущего цикла займет много часов, поскольку имеется более 21 000 строк. Можно ли это оптимизировать с помощью apply или numpy?

 count = 0
url = data['review_link']


for link in url:
    url = "http://{}".format(link)
    req = requests.get(url)
    best = BeautifulSoup(req.text, 'html')
    
    reviews = best.find_all('div', {'class' : 'review-detail'})
    
    for review in reviews:

        entry = {
            'artist' : safeFindText(review, 'ul', {'class' : 'artist-links artist-list single-album-tombstone__artist-links'}),
            'bnm' : safeFindText(review, 'p', {'class' : 'bnm-txt'}),
            'title' : safeFindText(review, 'h1', {'class' : 'single-album-tombstone__review-title'}),
            'score' : safeFindText(review, 'span', {'class' : 'score'}),
            'label' : safeFindText(review, 'li', {'class' : 'labels-list__item'}),
            'year' : safeFindText(review, 'span', {'class' : 'single-album-tombstone__meta-year'}),
            'author' : safeFindText(review, 'a', {'class' : 'authors-detail__display-name'}),
            'author_title' : safeFindText(review, 'span', {'class' : 'authors-detail__title'}),
            'genre' : safeFindText(review, 'a', {'class' : 'genre-list__link'}),
            'review_timestamp' : safeFindText(review, 'time', {'class' : 'pub-date'}),
            'review_abstract' : safeFindText(review, 'div', {'class' : 'review-detail__abstract'}),
            'review_text' : safeFindText(review,'div', {'class' : 'clearfix flex-md'})
            
            
                                   }
        pitchfork_dicts.append(entry)
        if count % 10 == 0:
            print("{} rows completed".format(count))
    count  = 1
 

Комментарии:

1. Фактический цикл, вероятно, не является узким местом, .apply не будет иметь заметного значения, действительно, он может быть немного медленнее. req = requests.get(url) вероятно, это узкое место, а не цикл по фрейму данных. Или, может быть, все, что происходит внутри safeFindText . Также неясно, как вы будете использовать numpy здесь, похоже, вы просто извлекаете текстовые данные с веб-сайтов, numpy для кода, который будет выражен в терминах числовых операций над многомерными массивами, линейной алгеброй и т. Д

2. Вы можете одновременно отправлять несколько запросов к API, если это ваше узкое место.

Ответ №1:

Проблема в том, что ваша программа простаивает, пока запросы ожидают ответа. Поскольку ожидание сетевого ввода-вывода, вероятно, является узким местом, я не думаю, что apply или numpy значительно ускорят вас. Две оптимизации, о которых я могу подумать, заключаются в том, чтобы либо использовать ThreadPool, который заботится о выполнении всех запросов, в то время как ваш основной цикл просматривает его список. Или использовать async для асинхронного выполнения запросов, чтобы, пока он ожидает ответов, вы могли продолжить работу со списком.

Для пула потоков вы можете создать потокобезопасную очередь, в которую отправляется ваш основной поток. А затем пул потоков потоков, который выводит следующий элемент и выполняет запрос и обрабатывает результат.