Nano Hash - криптовалюты, майнинг, программирование

Использование многопроцессорности для улучшения очистки Википедии с помощью BeautifulSoup

Я использую BeautifulSoup, чтобы собрать базовую информацию с нескольких страниц Википедии. Программа работает, но медленно (около 20 минут на 650 страниц). Я пытаюсь использовать многопроцессорность, чтобы ускорить это, но это не работает должным образом. Он либо зависает и ничего не делает, либо царапает только первую букву имени каждой страницы.

Код очистки, который я использую:

#dict where key is person's name and value is proper wikipedia url formatting
all_wikis = { 'Adam Ferrara': 'Adam_Ferrara',
              'Adam Hartle': 'Adam_Hartle',
              'Adam Ray': 'Adam_Ray_(comedian)',
              'Adam Sandler': 'Adam_Sandler',
              'Adele Givens': 'Adele_Givens'}
bios = {}
def scrape(dictionary):
    for key in dictionary:
        #search each page
        page = requests.get(("https://en.wikipedia.org/wiki/" + str(key)))
        data = page.text
        soup = BeautifulSoup(data, "html.parser")
        #get data
        try:
            bday = soup.find('span', attrs={'class' : 'bday'}).text
        except:
            bday = 'Birthday Unknown'
        try:
            birthplace = soup.find('div', attrs={'class' : 'birthplace'}).text
        except:
            birthplace = 'Birthplace Unknown'
        try:
            death_date = (soup.find('span', attrs={'style' : "display:none"}).text
                                                                            .replace("(", "")
                                                                            .replace(")", ""))
            living_status = 'Deceased'
        except:
            living_status = 'Alive'
        try:
            summary = wikipedia.summary(dictionary[key].replace("_", " "))
        except:
            summary = "No Summary"
        bios[key] = {}
        bios[key]['birthday'] = bday
        bios[key]['home_town'] = birthplace
        bios[key]['summary'] = summary
        bios[key]['living_status'] = living_status
        bios[key]['passed_away'] = death_date

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

from multiprocessing import Pool, cpu_count

if __name__ == '__main__':
    pool = Pool(cpu_count())
    results = pool.map(func=scrape, iterable=all_wiki)
    pool.close()
    pool.join()

Есть ли лучший способ структурировать мой сценарий, чтобы обеспечить многопроцессорность?


  • Добро пожаловать в StackOverflow! Я думаю, вам нужно обновить page = requests.get(("https://en.wikipedia.org/wiki/" + str(key))) до page = requests.get(("https://en.wikipedia.org/wiki/" + str(dictionary[key]))) 08.11.2019
  • Можете ли вы опубликовать ожидаемую структуру вывода для этого примера dict? Сама веб-очистка, похоже, не извлекает правильные данные, и я также могу предложить исправление для этого (в моем ответе обсуждаются только проблемы с MP). Спасибо. 08.11.2019

Ответы:


1

Здесь есть несколько проблем:

  • dictionary - это каждый строковый ключ в all_wikis dict. Когда вы затем перебираете эту строку с помощью for key in dictionary:, вы получаете доступ к каждому символу в строке. Ваш первый запрос к https://en.wikipedia.org/wiki/A, что не является желаемым результатом.
  • str(key) не очень полезно, даже если dictionary было именем. Нам нужно найти правильный URL-адрес с помощью all_wikis[name]. Кроме того, избегайте общих переменных, таких как dictionary.
  • Поскольку вы используете многопроцессорную обработку данных, такие данные, как bios, должны быть общими, чтобы ими можно было манипулировать. Проще всего просто использовать возвращаемое значение функции map, которое представляет собой совокупность всех возвращаемых значений рабочей функции.
  • У вас проблемы с логикой. wikipedia.summary не определено. Не будучи уверенным в точном желаемом результате, он сообщает об умершем Адаме Сэндлере. Я оставлю это как упражнение для читателя, так как этот вопрос в основном касается многопроцессорности.
  • Я не уверен, что многопроцессорность здесь так же желательна, как и многопоточность. Поскольку ваш процесс будет заблокирован, отправляя запросы в 99% случаев, держу пари, вы можете повысить эффективность, используя гораздо больше потоков (или процессов), чем количество ядер, которые у вас есть. Многопроцессорная обработка больше подходит, когда вы выполняете работу, связанную с процессором, что здесь не так; очень мало времени будет потрачено на сам процесс Python. Я бы рекомендовал тестировать код, увеличивая количество процессов (или потоков, если вы проводите рефакторинг для этого) сверх количества ядер, пока вы не перестанете видеть улучшения.

Вот некоторый код, чтобы вы начали. Я придерживался многопроцессорности в соответствии с вашим примером и не настраивал логику веб-скрейпинга.

import requests
from bs4 import BeautifulSoup
from multiprocessing import Pool, cpu_count

all_wikis = {'Adam Ferrara': 'Adam_Ferrara',
             'Adam Hartle': 'Adam_Hartle',
             'Adam Ray': 'Adam_Ray_(comedian)',
             'Adam Sandler': 'Adam_Sandler',
             'Adele Givens': 'Adele_Givens'}

def scrape(name):
    data = requests.get("https://en.wikipedia.org/wiki/" + all_wikis[name]).text
    soup = BeautifulSoup(data, "html.parser")
    bio = {}

    try:
        bio['birthday'] = soup.find('span', attrs={'class': 'bday'}).text
    except:
        bio['birthday'] = 'Birthday Unknown'

    try:
        bio['home_town'] = soup.find('div', attrs={'class': 'birthplace'}).text
    except:
        bio['home_town'] = 'Birthplace Unknown'

    try:
        bio['passed_away'] = (soup.find('span', attrs={'style': "display:none"}).text
                                                                        .replace("(", "")
                                                                        .replace(")", ""))
        bio['living_status'] = 'Deceased'
    except:
        bio['living_status'] = 'Alive'

    bio['summary'] = "No Summary"
    return name, bio


if __name__ == '__main__':
    pool = Pool(cpu_count())
    bios = dict(pool.map(func=scrape, iterable=all_wikis))
    pool.close()
    pool.join()
    print(bios)
08.11.2019
  • Спасибо! Я исправил парсинг с помощью wptools, который хорошо работает с википедией, но изначально был слишком медленным. С многопроцессорной обработкой время сократилось до 10 минут для ~650 записей, чем я доволен. Я не очень хорошо знаком с многопоточностью, как вы думаете, можно было бы еще больше сократить время, используя это? 11.11.2019
  • Это стоит попробовать и довольно просто написать код, но всегда трудно предсказать, какого ускорения вы сможете достичь. Это зависит от того, сколько у вас ядер и сколько потоков/процессов вы можете создать, но в определенный момент отдача определенно уменьшается. Сколько процессов вы создаете в настоящее время для своего 10-минутного запуска? 11.11.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..