CoderCastrov logo
CoderCastrov
Анализ данных

Парсинг для начинающих с BeautifulSoup

Парсинг для начинающих с BeautifulSoup
просмотров
5 мин чтение
#Анализ данных

Табличный парсинг данных Covid-19 — использование worldometer в качестве источника

Парсинг веб-сайтов является одним из самых интересных аспектов науки о данных. Возможность проводить собственный анализ и прогнозирование данных любого веб-сайта делает эту область науки намного более захватывающей! Возможности для сбора данных с веб-сайтов с помощью этого процесса, называемого парсингом, безграничны. Однако это не так просто, как копирование и вставка в документ Word. Но благодаря гениальным людям в сообществе Python и правильному количеству библиотек, таких как Scrapy, Selenium и BeautifulSoup, процесс не слишком утомителен. В этой статье мы собираемся исследовать, как использовать BeautifulSoup для парсинга данных Covid-19 с worldometer.

В течение последнего года Covid-19 привлек внимание всего мира. Есть так много вопросов, на которые до сих пор нет ответов, о этом вирусе, который нанес ущерб миру. Поэтому буквально любой вид анализа может принести более глубокое понимание и полезные идеи для нас самих и, возможно, для общества. Поэтому я выбираю worldometer для этого руководства.


Давайте начнем!

Для начала импортируем необходимые библиотеки.

import pandas as pd
import numpy as np
from bs4 import BeautifulSoup
import requests
import html

Существует два варианта получения таблицы, один из которых намного проще и известен некоторым людям, но не мне. Метод read_html() используется для получения таблиц напрямую с веб-сайта без необходимости в дополнительной работе. Это легко работает, например, для таблиц на Википедии. Стоит попробовать, если вашей целью является переход к анализу, а не тратить энергию на изучение парсинга. Прокрутите вниз до Альтернативы 2, если вы хотите пропустить вперед и начать получать данные. Обратите внимание, что целью статьи является изучение парсинга с использованием BeautifulSoup, который я буду называть "Альтернатива 1".

Давайте сначала сохраните наш веб-сайт в переменную, скажем, url.

url = '[http://www.worldometers.info/coronavirus/'](http://www.worldometers.info/coronavirus/')

Мы собираемся вежливо получить HTML-контент с worldometer, используя requests. Requests используется для получения необработанных данных с веб-сайтов.

r = requests.get(url)

Альтернатива 1

Вот суп! Используя следующий код, мы получим содержимое нашего ответа, сохраненное в переменной "r". BeautifulSoup_ _в двух словах помогает отделить полезную информацию, такую как ссылки, текст, заголовки и т. д., от тегов Html, которые затем можно использовать для дальнейшего анализа. Функция lxml используется в качестве парсера для интерпретации Html кода.

soup = BeautifulSoup(r.text,'lxml')

Если вы попытаетесь вызвать переменную soup, вы увидите огромное количество информации. Нашей целью является получение только актуальной табличной информации, выполнив следующий код.

lst_crucial = [str(i) for i in list(soup.find_all('table')[0].find_all('td'))]

Итак, что у нас здесь? Вышеуказанный код сужает наш суп только до информации, которая нам нужна для создания фрейма данных, используя немного сложное списковое включение. Вы можете попробовать выполнить каждую из soup.find_all('table'), затем soup.find_all('table')[0], а затем (soup.find_all('table')[0].find_all('td') отдельно, чтобы понять, что именно мы сделали здесь.

soup.find_all('table'): Дает нам все таблицы на веб-странице, и нас интересует только первая, что приводит нас к

soup.find_all('table')[0]: Теперь, когда у нас есть вся информация, относящаяся к нужной нам таблице, мы можем дальше сузить ее только до данных. Нам не нужна информация о том, как стилизована таблица и т. д., поэтому мы сделаем следующее

(soup.find_all('table')[0].find_all('td'): "td" - это данные таблицы, и это единственная информация, которая нам нужна из всего супа. Заметьте, что использование этого кода устраняет теги "tr" и "th"?

Остальной код просто сохраняет каждый элемент актуальных данных в список, который я назвал "lst_crucial" (потому что этот список является основой для остального нашего кода) - в виде строки. Конечно, это также можно сделать в цикле, но я нахожу списковое включение более эффективным и элегантным.

Хорошо! У нас есть то, что нам нужно, давайте преобразуем список в таблицу! Для этого начнем с импорта re, а затем создадим пустой DataFrame. Re - это библиотека, которая позволяет нам использовать регулярные выражения для поиска необходимых элементов в строках.

import re
df = pd.DataFrame()

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

df['Страны'] = [''.join([re.findall('>(.*?)<', lst_crucial[i-13:i+1][0])[1]]) for i,v in enumerate(lst_crucial) if 'world-population' in v]

Действительно, еще одно списковое включение, и у нас будет еще 12 таких для каждого столбца, но все они очень похожи на этот. Что делает вышеуказанный код? Если вы изучите наш lst_crucial, вы заметите, что данные записаны построчно, и каждая строка заканчивается "общей численностью населения" страны с ссылкой href, начинающейся с "world-population" для каждой из них. Нашей целью является получение 13 элементов списка перед этим элементом и включение этого элемента, выполнив этот диапазон - i-13:i+1 ("i" - это индекс 13-го элемента и содержит "world-population"). Мы не хотим все элементы списка для нашего столбца "Страны", а только страны. Поэтому с помощью re.findall('>(.*?)<, lst_crucial[i-13:i+1][0])[1]]) мы фактически извлекаем все элементы между тегами, потому что именно там находятся страны, и мы делаем это только из первого элемента среди 13 элементов каждой строки, поэтому [0], и из трех групп элементов регулярного выражения, которые у нас есть между, мы хотим вторую группу - страны, поэтому [1].

Для всех остальных столбцов код следует аналогичной структуре. Следующий код предназначен для следующего столбца.

df['Всего случаев'] = [''.join([k for s in lst_crucial[i-13:i+1][1] for k in s if k.isdigit()]) for i,v in enumerate(lst_crucial) if 'world-population' in v]

В этом коде мы просто берем числовые элементы из второго диапазона из 13 элементов, составляющих строку, поэтому [1] - помните, что мы сделали то же самое для столбца "Страны", но использовали [0], так как это был первый элемент? ".join" в основном объединяет каждую цифру в одну строку, чтобы получить требуемое число. Мы продолжим делать то же самое для всех остальных столбцов, так как они все являются числовыми. Вот окончательный код:

GIF by Author`

Этого всего! У нас есть полный фрейм данных от worldometer на сегодня, готовый для дальнейшего анализа.

Альтернатива 2

Вместо вышеуказанной альтернативы мы можем попробовать этот метод, который может или не может сработать. Мы собираемся вызвать метод read_html() из библиотеки pandas на содержимом URL, которое мы предварительно сохранили в переменной "r". Давайте сохраним это как "dfs", так как в содержимом может быть несколько таблиц. Наконец, вызов dfs[0] дает нам первую таблицу, которая является для нас релевантной.

r = requests.get(url)
dfs = pd.read_html(r.text, attrs = {'id':'main_table_countries_today'})
dfs[0]

Ниже приведен фрагмент вывода.

Фото от автора

Вот и все на этот раз - оставайтесь на связи для следующей статьи об анализе данных о COVID