Как собрать данные для DS-проекта с помощью Python: 3 шага

Любой проект по науке о данных нуждается в данных. Чтобы извлечь их с сайта и создать необходимый набор, используются инструменты веб-скрейпинга.

Однако на одном сайте не всегда находятся все нужные данные либо там могут быть несоответствия, из-за которых можно извлечь только часть данных.

Так случилось со мной, когда я искал данные о футбольных матчах, проведенных на Чемпионатах мира с 1930 по 2022 год. Некоторые данные были извлечены, но не все. С помощью этого руководства мы извлечем остальные данные с нуля с помощью Selenium, чтобы в дальнейшем использовать их в проекте.

Шаг 1. Установка Selenium

Чтобы установить Selenium, откроем терминал и выполним следующую команду:

pip install selenium

Теперь загрузите версию Chromedriver, подходящую для вашего компьютера.

  • Проверьте версию вашего Google Chrome (нажмите на три точки, кликните на “help”, а затем выберите “about Google Chrome”).
  • Скачайте нужную версию Chromedriver здесь (после обновления Chrome скачайте файл снова).
  • Распакуйте скачанный файл и скопируйте путь к файлу Chromedriver.

Шаг 2. Веб-скрейпинг одной страницы

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

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
import pandas as pd
  • Selenium  —  для сбора данных.
  • Time  —  для добавления времени ожидания при автоматизации сайта.
  • Pandas  —  для организации извлеченных данных в датафреймы.

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

  • path  —  местонахождения файла Chromedriver.
  • web  —  сайт, который вы собираетесь скрейпить (мы будем скрейпить эту страницу).
  • driver  —  объект, который поможет проводить скрейпинг сайта.
path = # Здесь прописываем путь
service = Service(executable_path=path)
driver = webdriver.Chrome(service=service)
web = 'https://en.wikipedia.org/wiki/1982_FIFA_World_Cup'

Теперь, чтобы открыть Chromedriver и перейти на целевой сайт, выполним следующую строку кода:

driver.get(web)

Появится новое окно с сообщением “Chrome is controlled by automated test software” (“Chrome управляется автоматизированным тестовым программным обеспечением”).

Теперь нужно посмотреть HTML-код, стоящий за элементами, которые нужно извлечь. Для этого прокрутим страницу вниз, пока не найдем данные о футбольных матчах, затем щелкнем правой кнопкой мыши и выберем “Inspect”.

Откроются инструменты разработчика. Нужно нажать на кнопку выбора (значок курсора слева) и найти строку, содержащую информацию о футбольном матче.

После выделения строки получим HTML-элемент, который стоит за ней.

<tr style="font-size:90%">

Теперь, чтобы найти этот элемент с помощью Selenium, нужно создать его XPath. Вот синтаксис XPath:

Если заменить каждый элемент, получим следующее:

//tr[@style="font-size:90%"]

Создав XPath, мы можем использовать .find_elements для поиска такого элемента с помощью Selenium.

matches = driver.find_elements(by='xpath', value='//tr[@style="font-size:90%"]')

Переменная matches  —  это список, содержащий 48 строк/матчей, перечисленных на сайте. Пройдясь по этому списку, получим все элементы td, поскольку они являются дочерними узлами элемента tr, XPath которого мы создали ранее.

Элементы td содержат данные о команде хозяев поля, счете и команде-гостье. Мы можем получить эти данные с помощью следующих XPath.

  • /td[1]  —  команда хозяев поля.
  • /td[2]  —  счет.
  • /td[3]  —  команда-гостья.

Пройдемся по matches и сохраним данные в пустых списках, которые назовем home (хозяева), score (счет) и away (гости).

home = []
score = []
away = []

for match in matches:
home.append(match.find_element(by='xpath', value='./td[1]').text)
score.append(match.find_element(by='xpath', value='./td[2]').text)
away.append(match.find_element(by='xpath', value='./td[3]').text)

Обратите внимание на добавление . перед исходным /td XPath. Это связано с тем, что теперь используется не driver.find_element, а match.find_element (символ . указывает на то, что поиск начинается с узла match).

Кроме того, добавляется атрибут text, чтобы получить текст, содержащийся в узле (например, Англия, 3–1, Франция).

Наконец, создаем датафрейм из списков home, score и away. Добавляем новый столбец year (год), время ожидания  —  2 секунды (это необязательно) и выходим из driver’а.

dict_football = {'home': home, 'score': score, 'away': away} 
df_football = pd.DataFrame(dict_football)
df_football['year'] = 1982
time.sleep(2)
driver.quit()

Для экспорта датафрейма используем .to_csv.

df_football.to_csv("fifa_worldcup_missing_data.csv", index=False)

Экспортированные данные должны выглядеть так, как показано на изображении ниже, и содержать 48 строк.

Код, написанный до этих пор, можно найти на GitHub. Теперь, немного подправив код, проведем скрейпинг уже не одной, а нескольких страниц.

Шаг 3. Создание функции для скрейпинга нескольких страниц

Самое интересное в веб-скрейпинге  —  возможность провести его на нескольких страницах после выполнения на одной (при условии, что все страницы имеют одинаковую структуру).

Вот функция, которая позволяет это сделать:

def get_misssing_data(year):
web = f'https://en.wikipedia.org/wiki/{year}_FIFA_World_Cup'

driver.get(web)
matches = driver.find_elements(by='xpath', value='//tr[@style="font-size:90%"]')

home = []
score = []
away = []

for match in matches:
home.append(match.find_element(by='xpath', value='./td[1]').text)
score.append(match.find_element(by='xpath', value='./td[2]').text)
away.append(match.find_element(by='xpath', value='./td[3]').text)

dict_football = {'home': home, 'score': score, 'away': away}
df_football = pd.DataFrame(dict_football)
df_football['year'] = year
time.sleep(2)
return df_football

Обратите внимание, что данная функция использует year в качестве входных данных. Переменная year помещена в ссылку web и столбец df_football[‘year’]. Остальное остается неизменным.

Запустив get_misssing_data(1982), получим тот же результат, что и в шаге 2.

Чтобы извлечь данные с нескольких страниц, создадим список years, содержащий все годы, в которые проводился Чемпионат мира.

years = [1930, 1934, 1938, 1950, 1954, 1958, 1962, 1966, 1970, 1974,
1978, 1982, 1986, 1990, 1994, 1998, 2002, 2006, 2010, 2014,
2018]

Теперь с помощью генератора списков проскрейпим страницу, соответствующую каждому году, и сохраним данные в списке с именем fifa. Соберем все списки вместе с помощью .concat и, наконец, экспортируем эти данные в CSV.

fifa = [get_misssing_data(year) for year in years]
driver.quit()
df_fifa = pd.concat(fifa, ignore_index=True)
df_fifa.to_csv("fifa_worldcup_missing_data.csv", index=False)

Теперь в CSV-файле должны быть сотни строк, содержащих все извлеченные данные.

Поздравляем! Вы научились создавать датасеты с помощью Selenium.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Frank Andrade: How to Collect Data for a Data Science Project with Python (in 3 Steps)

Предыдущая статьяКак ускорить сайт с помощью Varnish HTTP Cache и Docker
Следующая статья5 популярных пакетов и фреймворков Node.js