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

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

  • Запросы
  • КрасивыйСуп

В этом примере мы будем использовать 250 лучших фильмов IMDb. Вы можете следить в этой тетради kaggle!

Получение названия каждого фильма

Мы быстро перейдем к получению основной информации, так как это относительно просто. Если вам нужны подробности, я рассказал об этом в предыдущей статье на Medium.

Мы видим, что вся информация о фильме находится в теле основной таблицы:

У каждого фильма есть строка в этой таблице. Внутри этих строк есть столбцы. Столбец, содержащий название фильма, имеет класс titleColumn:

Отсюда легко получить название фильма. Мы можем просто использовать библиотеку запросов, чтобы получить страницу и выполнить итерацию по строкам. Для каждой строки мы можем перейти к столбцу title и получить название фильма внутри тега <a>:

Точно так же мы можем получить год выпуска в том же столбце, который находится внутри тега <span>:

Погружение глубже

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

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

К счастью, ссылка на эту страницу находится прямо на главной странице топ-250. Щелкнув по названию фильма, мы отправимся сюда. Если мы откроем DevTools (нажмите 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.

Конечно, мы знаем, что в фильме их может быть несколько, что показано на скриншотах «Крестного отца» выше. Итак, нам нужно перебирать жанры. Мы можем сделать это с помощью метода «find_all» и некоторого понимания списка:

И, наконец, мы можем привязать его к основным названиям фильмов и датам выхода:

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

Заключение

Это охватило довольно много, теперь вы должны быть в состоянии:

  • Запрос веб-страницы
  • Извлечь информацию с этой страницы
  • Найдите другие веб-страницы, содержащие нужную вам информацию
  • Соберите информацию с этих страниц

Практически на любом сайте. Дайте мне знать, если у вас есть какие-либо вопросы в комментариях!

Если вам это помогло, подпишитесь на меня в Twitter, чтобы получать больше ежедневных советов и статей по программированию.