Иерархический парсинг веб-страниц с помощью Python
Одна из наиболее сложных задач при парсинге веб-страниц - это работа с иерархическими данными. То есть данными, которые находятся на разных страницах.
Если вы ищете простой способ получить данные с каждой страницы без ручной обработки, то не ищите дальше. Мы будем использовать две популярные библиотеки Python для этой цели:
- Requests
- BeautifulSoup
В этом примере мы будем использовать Топ-250 фильмов IMDb. Вы можете следовать за нами в этой записной книжке Kaggle!
Получение названия каждого фильма
Мы быстро рассмотрим получение основной информации, так как это относительно просто. Если вам нужны более подробные сведения, я рассмотрел это в предыдущей статье на Medium.
Мы видим, что вся информация о фильмах находится в основном теле таблицы:
Каждый фильм имеет строку в этой таблице. Внутри этих строк есть столбцы. Столбец, который содержит название фильма, имеет класс "titleColumn":
Теперь получение названия фильма здесь легко. Мы можем просто использовать библиотеку requests для получения страницы и перебирать строки. Для каждой строки мы можем перейти к столбцу с названием и получить название фильма внутри тега <a>
:
Аналогично, мы можем получить год выпуска в том же столбце, который находится внутри тега <span>
:
Углубляемся в изучение
Предположим, нам нужна дополнительная информация о каждом фильме, которая не указана на странице списка Топ-250. Мы хотим добавить жанр фильма, который можно найти на странице каждого отдельного фильма:
В нижнем левом углу скриншота мы видим категории жанров, к которым принадлежит фильм. Поэтому нам нужно перейти на каждую отдельную страницу фильма, чтобы получить эту информацию.
К счастью, ссылка на страницу находится прямо на главной странице Топ-250. Нажатие на название фильма отправит нас сюда. Если мы откроем инструменты разработчика (нажмите F12 в браузере), мы увидим, что эта ссылка находится внутри тега <a>
, который мы использовали для получения названия фильма:
Ссылка находится в части "href" тега <a>
. К счастью, BeautifulSoup предоставляет нам инструмент для извлечения этой части тега:
link = item.find('a')['href']
Это очень похоже на запись, используемую для среза строк или списков. В этом случае мы можем получить данные из разных элементов внутри тега.
Запрос страницы каждого фильма
В нашем случае нам нужно получить это для каждого фильма в списке, что означает, что мы должны перебирать ранее созданные строки:
for row in rows:
link = column.a['href']
И мы можем вывести ссылки на каждый фильм:
Ссылки не имеют длинной строки запроса, которую мы видели в DevTools, однако они работают так же и перенаправляют нас на правильную страницу.
Теперь нам просто нужно запросить эту страницу, имейте в виду, что это не полная ссылка. Мы должны добавить часть домена:
for row in rows:
link = column.a['href']
movie_page = requests.get(f'https://imdb.com/{link}').content
После получения содержимого страницы нам нужно его разобрать, чтобы получить раздел с жанром:
for row in rows:
link = column.a['href']
movie_page = requests.get(f'https://imdb.com/{link}').content
movie_soup = BeautifulSoup(movie_page, 'html.parser')
Поиск жанров фильмов
Теперь нам просто нужно выяснить, где находится название жанра на странице:
Таким образом, каждый жанр находится внутри тега <a>
с длинным именем класса. Это можно легко добавить к итерации по строкам:
for row in rows:
link = column.a['href']
movie_page = requests.get(f'https://imdb.com/{link}').content
movie_soup = BeautifulSoup(movie_page, 'html.parser')
genre = movie_soup.find('span', 'sc-16ede01-3 bYNgQ ipc-chip ipc-chip--on-baseAlt')
Если мы выведем жанр на этом этапе, мы получим неожиданный результат:
Мы выводим только один жанр для каждого фильма. Конкретно, первый жанр в html.
Конечно, мы знаем, что у фильма может быть несколько жанров, что показано на скриншотах The Godfather выше. Поэтому нам нужно пройти по жанрам. Мы можем сделать это, используя метод "find_all" и немного спискового включения:
И, наконец, мы можем присоединить это к основным названиям фильмов и датам выпуска:
Это самый глубокий уровень, на котором мы остановимся в этом примере, но вы можете уйти гораздо глубже, чем на два уровня в иерархии, используя этот метод.
Заключение
В этом руководстве было рассмотрено многое, и теперь вы должны быть в состоянии:
- Запросить веб-страницу
- Извлечь информацию с этой страницы
- Найти другие веб-страницы, содержащие нужную информацию
- Собрать информацию с этих страниц
На практически любом веб-сайте. Если у вас есть вопросы, пожалуйста, задавайте их в комментариях!
_Если вам это помогло, подумайте о __подписке на мой твиттер _для получения ежедневных советов и статей по программированию.