CoderCastrov logo
CoderCastrov
Питон

Парсинг веб-страниц с помощью Python и Beautiful Soup

Парсинг веб-страниц с помощью Python и Beautiful Soup
просмотров
5 мин чтение
#Питон
Table Of Content

    В последнее время я работал над приложением для корреляции данных под названием BANaNAS. Цель проекта заключалась в создании интерфейса, в котором пользователи могли бы запрашивать как можно больше метрик в широком диапазоне категорий. Например, вы могли бы отслеживать экспорт овса из Италии по отношению к распространенности туберкулеза в Гане за последние 20+ лет. Затем отфильтровать эти два набора данных, чтобы увидеть, насколько они более тесно коррелируют в годах, когда произошло, скажем, убийство президента или крупное извержение вулкана. Предпосылка была смехотворной, но это оказалось отличной возможностью узнать больше о стратегической архитектуре бэкэнда.

    Нашей задачей было найти дешевые/бесплатные API с большими наборами данных, но когда мы стали искать более редкие данные, такие как природные катастрофы или убийства, мы обнаружили, что на самом деле не существует никакого подходящего API. Удивление удивление. Поэтому мы прибегли к парсингу данных. Мне очень понравился весь процесс написания скриптов для получения огромных наборов данных, и я хотел поделиться этим с теми, кто интересуется тем, как начать парсить в Python.

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

    Примечание: Вы можете найти полный проект на моем Github.

    Прежде всего, установите Python, если еще не установили. (Если вы используете Windows, убедитесь, что добавили Python в переменную среды PATH)

    Затем откройте терминал, чтобы настроить проект. Если вы никогда не работали с виртуальными средами в Python, вы можете ознакомиться с документацией здесь. Это похоже на команду npm init в среде Node.js, и она позволит нам устанавливать пакеты в этой конкретной папке, а не глобально.

    python -m venv scraping-tutorial //это создает нашу виртуальную среду
    source scraping-tutorial/bin/activate //это активирует нашу виртуальную среду

    Затем нам понадобится установить несколько соответствующих зависимостей и создать наш файл скрипта. Requests - это библиотека HTTP для Python, которая позволит нам получать веб-страницы. А Beautiful Soup - это библиотека Python, которая упрощает извлечение данных из HTML-файлов.

    cd scraping-tutorial
    touch wiki-scrape.py
    pip install requests beautifulsoup4

    Хорошо, теперь мы готовы начать писать скрипт. Большая часть следующего кода - это просто шаблонный код для нашего файла wikiscrape.py, и я объясню его по мере продвижения.

    json - это библиотека, встроенная в Python, которая позволит нам записывать все наши полученные данные в файл .json, чтобы они сохранялись после выполнения программы.

    import json
    import requests
    from bs4 import BeautifulSoup

    Теперь мы определим наш URL и получим его, затем передадим его через html-парсер Beautiful Soup.

    url = "https://en.wikipedia.org/wiki/List_of_assassinations"
    
    page = requests.get(url)
    
    soup = BeautifulSoup(page.text, 'html.parser')

    Теперь у нас есть весь HTML и мы можем начать извлекать данные из него.

    Краткое пояснение, основной процесс парсинга данных выглядит так:

    Итак, давайте взглянем на нашу страницу Википедии и попробуем определить шаблон.

    layout of wikipedia table

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

    Из этого мы знаем, что у нас будет 2 цикла. Первый будет перебирать каждую страну на странице, а второй будет вложен в первый и будет перебирать каждую строку таблицы страны.

    Теперь давайте откроем инструменты разработчика Chrome и проверим названия стран.

    inspect country name elements

    Похоже, что названия стран - это все элементы span, вложенные в элементы h3. После каждого тега h3 следует таблица, и эта структура повторяется. Теперь, поскольку я ленивый, я использовал поиск элементов HTML с помощью сочетания клавиш ctrl+f в инструментах разработчика, и, к счастью, названия стран - это единственные теги h3 на странице. Что облегчает нам жизнь. Итак, давайте получим все теги h3 из нашего разобранного HTML.

    countries = soup.find_all('h3')

    Стоит отметить на этом этапе, что у нас теперь есть весь элемент h3, от открывающего тега до закрывающего тега, включая все вложенные элементы.

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

    data = {}

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

    {
        название страны: {
          дата: жертва,
          дата: жертва
        },
        название страны: {
          дата: жертва,
          дата: жертва
        }
    }

    Пришло время начать писать циклы. Хорошая часть следующего синтаксиса Python и Beautiful Soup заключается в том, что большая часть из них понятна сама по себе, и я отмечу те части, которые не очевидны.

    for country in countries:
        countryName = country.span.text.strip()
        countryAssassinations = {} //где мы будем записывать все свойства дата:жертва

    Метод .strip() удаляет начальные и конечные символы, такие как пробелы и переносы строк.

    Теперь, когда у нас есть название страны, мы хотим получить фактические данные из таблицы. Давайте получим тело таблицы.

        table = country.find_next('tbody')

    Примечание: если вы впервые пишете скрипт на Python, обратите внимание на отступы, они определяют уровень области видимости вашего кода.

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

    table structure

    Первый <td> содержит span с датой, которую мы хотим сохранить, и если вы откроете инструменты разработчика и развернете второй тег td, вы увидите, что он содержит данные о жертве.

    Давайте напишем наш вложенный цикл.

        for row in table:
            date = row.find_next('td').text.strip()
            victim = row.find_next('td').find_next('td').text.strip()

    Примечание: поскольку мы обращаемся только ко второму экземпляру td, мне не важно написать .find_next дважды. Если вам нужно получить доступ к данным, которые находятся на n элементов от вашего сохраненного элемента, ознакомьтесь с этим постом.

    Теперь, когда мы запустим этот скрипт, у нас будут все названия стран, даты и жертвы. Давайте сохраним их в соответствующие места.

            countryAssassinations[date] = victim
        
        data[countryName] = countryAssassinations //убедитесь, что вы перешли на один уровень отступа назад, чтобы эта строка была в области видимости внешнего цикла

    Отлично, теперь наш объект будет содержать все наши отформатированные данные при запуске скрипта. Последнее, что нужно сделать, это сохранить эти данные где-нибудь, чтобы они сохранялись после выполнения программы.

    with open('data.json, 'w') as dataFile:    json.dump(data, dataFile)

    Первая строка выше говорит скрипту открыть файл с именем data.json, и он создаст его для нас, если он не существует. 'w' говорит скрипту открыть файл в режиме записи. Мы сохраним ссылку на этот файл data.json в переменной, которую мы назовем dataFile. Вторая строка использует метод json.dump(), чтобы записать наш объект данных в файл data.json.

    Теперь это конец нашего скрипта. Мы можем открыть терминал и запустить скрипт из папки scraping-tutorial.

    python wiki-scrape.py

    Вы увидите файл data.json появится в корневом уровне вашей папки. Удачного парсинга!