В моей последней статье я обсуждал создание набора данных с использованием интерфейса прикладного программирования (API) и библиотек Python. API-интерфейсы позволяют нам легко извлекать очень полезную информацию с веб-сайта. Однако не все веб-сайты имеют API, и это затрудняет сбор соответствующих данных. В таком случае мы можем использовать веб-парсинг для доступа к содержимому веб-сайта и создания нашего набора данных.
Веб-парсинг - это метод, используемый для извлечения больших объемов данных с веб-сайтов, при котором данные извлекаются и сохраняются в локальном файле на вашем компьютере или в базе данных в формате таблицы (электронной таблицы). - WebHarvy
Как правило, веб-парсинг включает доступ к многочисленным веб-сайтам и сбор с них данных. Однако мы можем ограничиться сбором большого количества информации из одного источника и использовать его как набор данных. В этом конкретном примере мы исследуем Википедию. Я также объясню основы HTML, которые нам понадобятся. Полный проект доступен в виде записной книжки в репозитории Github Web Scraping using Python.
Этот пример предназначен только для демонстрации. Тем не менее, мы всегда должны следовать правилам веб-сайта, прежде чем сможем очистить этот веб-сайт и получить доступ к его данным в каких-либо коммерческих целях.
Это статья из 2 частей. В этой первой части мы рассмотрим, как получить данные с веб-сайта с помощью BeautifulSoup, а во второй части мы очистим собранный набор данных.
Определить содержание
Мы получим доступ к веб-странице Википедии Список стран и зависимостей по населению. На веб-странице есть таблица с названиями стран, их населением, датой сбора данных, процентом мирового населения и источником. А если мы перейдем на страницу любой страны, то вся информация о ней записана на странице со стандартным окном справа. В этом поле содержится много информации, такой как общая площадь, процент воды, ВВП и т. Д.
Здесь мы объединим данные с этих двух веб-страниц в один набор данных.
- Список стран. При переходе на первую страницу мы извлекаем список стран, их население и процент населения мира.
- Страна. Затем мы перейдем на страницу каждой страны и получим информацию, включая общую площадь, процент воды и ВВП (номинальный).
Таким образом, наш окончательный набор данных будет включать информацию о каждой стране.
Основы HTML
Каждая веб-страница, которую вы просматриваете в своем браузере, на самом деле структурирована на языке гипертекстовой разметки (HTML). Он состоит из двух частей: заголовок, который включает заголовок и любые операции импорта для стилизации и JavaScript, и тело, которое включает контент, отображаемый в виде веб-страницы. Нас интересует основная часть веб-страницы.
HTML состоит из тегов. Тег описывается открывающей <
и закрывающей >
угловой скобкой с именем тега внутри нее в качестве начала, в то время как он отмечает конец, если после открывающей угловой скобки стоит косая черта /
. Например, <div></div>
, <p>Some text</p>
и т. Д.
Есть два прямых способа получить доступ к любому элементу (тегу), присутствующему на веб-странице. Мы можем использовать id, который является уникальным, или мы можем использовать класс, который может быть связан с несколькими элементами. Здесь мы видим, что <div>
имеет атрибут id as base
, который действует как ссылка на этот элемент, в то время как все ячейки таблицы, отмеченные td
, имеют один и тот же класс с именем data
.
Обычно полезные теги включают:
<div>
: Всякий раз, когда вы включаете определенный контент, вы заключаете его вместе в один объект. Он может выступать в качестве родительского для множества различных элементов. Таким образом, если здесь будут применены некоторые изменения стиля, они также отразятся на его дочерних элементах.<a>
: ссылки описываются в этом теге, где веб-страница, которая будет загружена при нажатии этой ссылки, упоминается в ее свойствеhref
.<p>
: этот тег используется всякий раз, когда некоторая информация должна отображаться на веб-странице в виде блока текста. Каждый такой тег отображается как отдельный абзац.<span>
: Когда информация должна отображаться в строке, мы используем этот тег. Когда два таких тега размещаются рядом, они появляются в одной строке, в отличие от тега абзаца.<table>
: Таблицы отображаются в HTML с помощью этого тега, где данные отображаются в ячейках, образованных пересечением строк и столбцов.
Импортировать библиотеки
Сначала мы импортируем необходимые библиотеки, а именно numpy, pandas, urllib и BeautifulSoup.
- numpy: очень популярная библиотека, которая делает операции с массивами очень простыми и быстрыми.
- pandas: Это помогает нам преобразовывать данные в табличную структуру, чтобы мы могли манипулировать данными с помощью множества эффективно разработанных функций.
- urllib: мы используем эту библиотеку, чтобы открыть URL-адрес, из которого мы хотим извлечь данные.
- BeautifulSoup: Эта библиотека помогает нам получить структуру HTML страницы, с которой мы хотим работать. Затем мы можем использовать его функции для доступа к определенным элементам и извлечения соответствующей информации.
Понять данные
Первоначально мы определяем только базовую функцию чтения URL-адреса, а затем извлечения HTML-кода из него. Мы будем вводить новые функции по мере необходимости.
В функции getHTMLContent()
мы передаем URL. Здесь мы сначала открываем URL-адрес с помощью метода urlopen
. Это позволяет нам применять библиотеку BeautifulSoup для получения HTML с помощью парсера. Хотя доступно множество парсеров, в этом примере мы используем html.parser
, который позволяет нам анализировать файлы HTML. Затем мы просто возвращаем результат, который затем можем использовать для извлечения наших данных.
Мы используем эту функцию, чтобы получить HTML-контент для страницы Википедии со списком стран. Мы видим, что страны представлены в таблице. Итак, мы используем метод find_all()
, чтобы найти все таблицы на странице. Параметр, который мы передаем внутри этой функции, определяет возвращаемый элемент. Поскольку нам требуются таблицы, мы передаем аргумент как table
, а затем перебираем все таблицы, чтобы определить нужную.
Мы печатаем каждую таблицу с функцией prettify()
. Эта функция делает вывод более читаемым. Теперь нам нужно проанализировать вывод и посмотреть, в какой таблице есть данные, которые мы ищем. После тщательного изучения мы видим, что таблица с классом wikitable sortable содержит нужные нам данные. Таким образом, наш следующий шаг - получить доступ к этой таблице и ее данным. Для этого мы будем использовать функцию find()
, которая позволяет нам не только указывать элемент, который мы ищем, но также указывать его свойства, такие как имя класса.
Таблица в HTML состоит из строк, обозначенных тегами <tr></tr>
. В каждой строке есть ячейки, которые могут быть заголовками, определенными с помощью <th></th>
, или данными, определенными с помощью <td></td>
. Таким образом, чтобы получить доступ к веб-странице каждой страны, мы можем получить ее ссылку из ячеек в столбце страны таблицы (второй столбец). Итак, мы перебираем все строки в таблице и считываем данные второго столбца в переменной country_link
. Для каждой строки мы извлекаем ячейки и получаем элемент a
во втором столбце (нумерация в Python начинается с 0, поэтому второй столбец будет означать cell[1]
). Наконец, печатаем все ссылки.
Ссылки не включают базовый адрес, поэтому всякий раз, когда мы открываем любую из этих ссылок, мы добавляем https://en.wikipedia.org
в качестве префикса.
Хотя функция, которую я разработал для извлечения данных с веб-страниц каждой страны, может показаться небольшой, для нее было много итераций, прежде чем я доработал функцию. Давайте изучим это шаг за шагом.
На странице каждой страны справа есть информационное поле с девизом, названием, ВВП, территорией и другими важными характеристиками. Итак, сначала мы определили имя этого поля с помощью тех же шагов, что и раньше, и это была таблица с классом как infobox geography vcard
. Затем мы определяем переменную additional_details
для сбора всей информации, которую мы получим с этой страницы, в массиве, который мы затем можем добавить к списку набора данных стран.
Когда мы входим в режим проверки браузера Chrome (щелкните правой кнопкой мыши в любом месте и выберите параметр Inspect
) на странице страны, мы можем просмотреть классы для каждого заголовка в таблице. Нас интересуют четыре поля: Площадь - Общая площадь, Водные ресурсы (%) и ВВП (номинальный) - Всего, На душу населения.
Мы можем легко сделать вывод, что заголовки Area
и GDP (nominal)
имеют классы mergedtoprow
, а данные, которые мы хотим извлечь, имеют классы mergedrow
или mergedrowbottom
. Но мы не можем напрямую обратиться к какому-либо элементу данных, так как порядок их возникновения меняется в зависимости от страны. В некоторых странах может отсутствовать конкретное поле, и mergedrow
для total area
может быть 6-м, а для некоторых других - 7-м. Таким образом, нам нужно сначала увидеть текст для mergedtoprow
, и если он соответствует либо площади, либо ВВП (номинальному), мы должны прочитать и собрать эти данные.
Кажется достаточно простым, но когда я попробовал, я сразу же увидел проблему, поскольку water (%)
для некоторых стран было больше 100. Это невозможно, и, следовательно, мы, должно быть, чего-то упускаем. Тогда я понял, в чем проблема. Видите ли, если мы прочитаем два значения после заголовка «Площадь» и значение воды отсутствует, мы неправильно прочитаем первое значение численности населения, что приведет к неверным данным. В результате нам нужно убедиться, что когда заголовок Population
идентифицирован, мы перестаем читать значения.
Теперь мы можем просто добавить все наши знания к функции getAdditionalDetails()
. Мы определяем переменную read_content
, чтобы отмечать, читаем мы следующее значение или нет. Здесь мы используем три типа функций, помимо описанных ранее:
get()
: Это позволяет нам не только найти, но и получить ссылку на конкретный элемент.get_text()
: получает значение, которое присутствует в открывающем и закрывающем тегах элемента.strip()
: удаляет любые дополнительные начальные и конечные пробелы, которые могут присутствовать в тексте. Мы также можем указать любое конкретное значение, которое мы могли бы пожелать удалить, например, в нашем случае символ новой строки\n
.
Обходя все строки в таблице, итератор проверяет, соответствует ли текущая строка заголовку, соответствующему Площадь или GDP (номинальный), и начинает чтение. В режиме чтения он проверяет, является ли новый элемент «Общая площадь» или «Всего», и если да, он считывает его и продолжает считывать, чтобы при следующем прогоне считать воду (%) или ВВП на душу населения соответственно.
Мы используем try
и except
, чтобы гарантировать, что даже если мы пропустим определенные значения, весь наш процесс не закончится. Это еще один урок, который я усвоил, просматривая полный список стран. В некоторых странах нет всей необходимой нам информации, или, возможно, мы не можем найти таблицу с нужным названием. В таком случае наш процесс может выдать ошибку, которую мы должны уловить, чтобы вернуть пустой массив и позволить процессу продолжиться для других стран.
Создать набор данных
Наконец, теперь мы знаем, какую информацию нам нужно собирать, а также как ее собирать.
Сначала мы читаем каждую строку таблицы из списка стран и собираем название каждой страны, численность населения и% населения мира. Затем мы используем ссылку, чтобы получить все дополнительные сведения, включая общую площадь, воду (%), общий ВВП и ВВП на душу населения. Если, однако, дополнительная информация меньше 4, значит, информация для этой страны отсутствует, и мы не используем эти данные. В противном случае мы добавляем всю эту информацию в массив data_content
, который компилируется в dataset
фрейм данных.
Затем мы читаем заголовки таблицы и добавляем заголовки для 4 дополнительных столбцов. Они действуют как заголовки для нашего набора данных, который мы экспортируем в файл .CSV, который можно найти здесь.
Несмотря на то, что наш набор данных теперь готов, он не в самом удобном формате. Нам нужно очистить этот набор данных, используя правильное форматирование, унифицировав метрики и удалив ненужные знаки и значения. Мы расскажем об этом во второй части статьи.
Надеюсь, вам понравилась моя статья. Пожалуйста, не стесняйтесь обращаться к нам и делиться своими мыслями.