В этом сообщении показано, как создать набор данных о фильмах с помощью Python и API OMDb. Это будет сделано с использованием списка извлеченных названий фильмов, показанных в предыдущем посте «movie-data-collection-part-1-web-scraping-using-python».

Во-первых, в нем представлены различные методы сбора или парсинга данных. Во-вторых, будет кратко рассмотрен API OMDb. Наконец, показано, как создается набор данных с помощью Python.

Сбор онлайн-данных

Сбор онлайн-данных, также называемый парсингом, часто включает в себя извлечение неорганизованных данных и организацию их в виде электронной таблицы. Существует несколько способов сбора данных из онлайн-источников. Среди них ручное копирование и вставка, синтаксический анализ HTML, синтаксический анализ DOM и использование существующего веб-API¹.

Копирование и вставка вручную просто включает копирование значения из источника в Интернете и вставку его в электронную таблицу, например. превосходить

Синтаксический анализ HTML включает в себя использование базовой структуры, из которой состоит веб-страница, и преобразование ее во что-то, с чем может работать программа. Веб-страница состоит из тегов, атрибутов и элементов. Разбор HTML-документа с помощью языка программирования позволяет распознавать составляющие страницы и извлекать из нее данные. Распространенным способом в Python является использование библиотеки BeatuifulSoup.

Синтаксический анализ DOM включает преобразование веб-страницы в логическую структуру, обеспечивающую доступность и манипулирование². Используя дополнительные инструменты, такие как Xpath, вы можете извлечь из него данные. Это отличный метод для парсинга динамических веб-страниц. В Python для этого можно использовать библиотеку Selenium.

Иногда разработчики могут использовать существующие веб-API. Затем разработчики могут напрямую взаимодействовать с базой данных и извлекать данные, которые существуют среди многих других для Twitter и Google Maps. Эти API используют стандартные методы и документацию о том, как извлекать, публиковать или удалять информацию.

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

API OMDb

OMDb (открытая база данных фильмов) RESTful API. Это веб-сервис, который позволяет вам получить доступ к информации о фильме, указав название фильма или идентификатор imdb. На веб-сайте вы можете запросить бесплатный ключ API, который позволит вам получить доступ

API, сокращенно от интерфейса прикладного программирования, — это программное обеспечение, которое обеспечивает общность между различными программными системами, позволяя им обмениваться информацией друг с другом³.

REST или Передача репрезентативного состояния просто относится к архитектурному дизайну API. Как правило, эти APIS используют HTTP (протокол передачи гипертекста) и используют стандартные методы, такие как GET, POST, PUT и DELETE⁴.

Всякий раз, когда предоставляется название фильма или идентификатор imdb, OMDdb возвращает изображение объекта JSON ниже⁵. Для получения дополнительной информации https://www.omdbapi.com/.

{"Title":"The Avengers",
"Year":"2012",
"Rated":"PG-13",
"Released":"04 May 2012",
"Runtime":"143 min",
"Genre":"Action, Sci-Fi",
"Director":"Joss Whedon",
"Writer":"Joss Whedon, Zak Penn",
"Actors":"Robert Downey Jr., Chris Evans, Scarlett Johansson",
"Plot":"Earth's mightiest heroes must come together and learn to fight as a team if they are going to stop the mischievous Loki and his alien army from enslaving humanity.","Language":"English, Russian, Hindi","Country":"United States","Awards":"Nominated for 1 Oscar. 38 wins & 80 nominations total","Poster":"https://m.media-amazon.com/images/M/MV5BNDYxNjQyMjAtNTdiOS00NGYwLWFmNTAtNThmYjU5ZGI2YTI1XkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_SX300.jpg",
"Ratings":[{"Source":"Internet Movie Database","Value":"8.0/10"},
{"Source":"Rotten Tomatoes","Value":"91%"},
{"Source":"Metacritic","Value":"69/100"}],
"Metascore":"69",
"imdbRating":"8.0",
"imdbVotes":"1,397,515",
"imdbID":"tt0848228",
"Type":"movie",
"DVD":"25 Sep 2012",
"BoxOffice":"$623,357,910",
"Production":"N/A",
"Website":"N/A",
"Response":"True"}

Как видно из выходных данных выше, каждое значение помечено. На момент написания OMDb API предлагает 1000 запросов в день бесплатно. Это можно увеличить, имея учетную запись Patreon.

Сбор данных с помощью Python

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

Запросы позволяют выполнять HTTP-запросы, предоставляя URL-адрес. HTTP-запросы выполняются клиентом к хосту, расположенному на сервере, для доступа к информации.

Pandasиспользуется для сохранения данных во фрейме данных (или в структуре, подобной электронной таблице).

В приведенном ниже блоке кода показано, как извлечь данные с помощью API для одного фильма.

Сбор данных для одного фильма

Сначала создается URL-адрес с использованием ключа API и названия фильма. Обратите внимание, что ключ API хранится в переменной с именем api_key. Как упоминалось ранее, персональный ключ можно запросить на веб-сайте.

Используя функцию get(), данные можно получить, используя URL-адрес в качестве входных данных. объект ответа хранится в переменной ответа. Метод status_code можно использовать для определения того, был ли запрос успешным, это тот случай, когда он возвращает значение 200. С помощью метода json() можно просмотреть содержимое запроса. (Вы могли заметить, что объекты JSON напоминают словарь Python, состоящий из ключей и значений.)

#importing libraries 
import pandas as pd
import requests 

# Movie name 
movie_name = 'the Avengers'

#url 
url = 'https://www.omdbapi.com/?apikey='+ api_key + '={}'.format(movie_name)

response = requests.get(url)

print(response.status_code) 
print(response.json())
>>> print(response.status_code)
200

>>> print(response.json())
{'Title': 'The Avengers', 
'Year': '2012', 
'Rated': 'PG-13', 
'Released': '04 May 2012', 
'Runtime': '143 min', 
'Genre': 'Action, Sci-Fi', 
'Director': 'Joss Whedon', 
'Writer': 'Joss Whedon, Zak Penn', 
'Actors': 'Robert Downey Jr., Chris Evans, Scarlett Johansson', 
'Plot': "Earth's mightiest heroes must come together and learn to fight as a team if they are going to stop the mischievous Loki and his alien army from enslaving humanity.", 
'Language': 'English, Russian, Hindi', 'Country': 'United States', 
'Awards': 'Nominated for 1 Oscar. 38 wins & 80 nominations total', 
'Poster': 'https://m.media-amazon.com/images/M/MV5BNDYxNjQyMjAtNTdiOS00NGYwLWFmNTAtNThmYjU5ZGI2YTI1XkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_SX300.jpg',
 'Ratings': [{'Source': 'Internet Movie Database', 'Value': '8.0/10'}, 
{'Source': 'Rotten Tomatoes', 'Value': '91%'}, 
{'Source': 'Metacritic', 'Value': '69/100'}],
 'Metascore': '69',
 'imdbRating': '8.0', 
'imdbVotes': '1,402,797',
 'imdbID': 'tt0848228',
 'Type': 'movie', 
'DVD': '25 Sep 2012',
 'BoxOffice': '$623,357,910', 
'Production': 'N/A', 
'Website': 'N/A', 
'Response': 'True'}

Сбор данных для нескольких фильмов

Как показано, API Omdb отвечает на входные данные для возврата данных характеристик фильма. Поэтому для создания набора данных требуется коллекция названий фильмов. Есть несколько способов получить названия фильмов (например, просто спросите в chatGPT3). В предыдущем посте «кино-данные-сбор-часть-1-веб-скрейпинг-использование-питона». Там Википедия была очищена от названий фильмов с помощью BeautifulSoup. вывод сохраняется в переменной movie_names как объект pd.Series.

#Series containing movie names 
movie_names
>>> movie_names
2                  Digger
3               Detention
4            Deathstalker
               ...
57399         The Cleaner
57400             Crashout
57401             Cheetah
57402         The Contact
57403        The Champion
Length: 57404, dtype: object

Создание набора данных

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

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

  • Список unique_keys, в котором хранятся все уникальные ключи данных, возвращенные ответами JSON. Они будут служить именами столбцов фрейма данных (или метками). Это необходимо, потому что не каждый запрос возвращает точные ключи.
  • json_responses — это список, содержащий объекты JSON, где каждый объект — это данные фильма, возвращаемые запросом get().
#Takes a list of movie names and returns features using the API 
def get_movie_data(movie_names):

    #initiate empty list to capture all json 
    json_responses = []

    #initiate empty list that stores a possible feature 
    possible_keys = []

    #iterate through movie list 
    for name in movie_names:

        #Request movie title using omdbAPI
        response = requests.get(
            'https://www.omdbapi.com/?apikey='+ api_key + '={}'.format(name)) 
            
        #Find all keys associated with the request extent the key list  
        possible_keys.extend(
            list(response.json().keys()))
        
        #append moviename
        nested_list_movies.append(response.json())

    #Remove all duplicated keys/features 
    unique_keys = set(possible_keys)

    return unique_keys, json_responses

unique_keys, json_responses = get_movie_data(subset_movie_names)
>>> unique_keys
{'Awards', 'Year', 'Genre', 'Metascore', 'imdbID', 'Title', 'Language', 'Production', 'Runtime', 'Actors', 'Country', 'Released', 'Plot', 'Website', 'BoxOffice', 'Error', 'Poster', 'Ratings', 'DVD', 'Writer', 'Response', 'totalSeasons', 'Rated', 'imdbRating', 'imdbVotes', 'Type', 'Director'}

>>> json_responses[4:6]
[{'Title': 'Deathstalker', 'Year': '1983', 'Rated': 'R', 'Released': '16 Sep 1983', 'Runtime': '80 min', 'Genre': 'Action, Adventure, Fantasy', 'Director': 'James Sbardellati', 'Writer': 'Howard R. Cohen', 'Actors': 'Rick Hill, Barbi Benton, Richard Brooker', 'Plot': 'A lone warrior nicknamed Deathstalker is sent by a witch on a quest to find a sword, a chalice, and an amulet, two of which are held by the wicked king and sorcerer, Munkar.', 'Language': 'English', 'Country': 'United States, Argentina', 'Awards': 'N/A', 'Poster': 'https://m.media-amazon.com/images/M/MV5BNzJlMDEwMTgtMGI5Ny00ODAzLThhM2UtYmRkYjc3OTRiZDQ0XkEyXkFqcGdeQXVyMTQ2MjQyNDc@._V1_SX300.jpg', 'Ratings': [{'Source': 'Internet Movie Database', 'Value': '4.6/10'}], 'Metascore': 'N/A', 'imdbRating': '4.6', 'imdbVotes': '5,524', 'imdbID': 'tt0087127', 'Type': 'movie', 'DVD': '18 Jun 2018', 'BoxOffice': '$11,919,250', 'Production': 'N/A', 'Website': 'N/A', 'Response': 'True'} 
,{'Title': 'Daadi Maa', 'Year': '1966', 'Rated': 'Not Rated', 'Released': 'N/A', 'Runtime': '171 min', 'Genre': 'Action, Comedy, Drama', 'Director': 'L.V. Prasad', 'Writer': 'Mukhram Sharma', 'Actors': 'Ashok Kumar, Bina Rai, Dilip Raj', 'Plot': 'Pratap lives a wealthy lifestyle in a mansion along with his mother, Maharani. He is married to Parvati but the couple are childless. Then differences arise between the two on one hand, and Maharani and Pratap on the other. Parvat...', 'Language': 'Hindi', 'Country': 'India', 'Awards': 'N/A', 'Poster': 'https://m.media-amazon.com/images/M/MV5BZDI3MDIyODYtOTdlYi00MjcwLWE1MWMtMDk1Yjg1MzhjOTlhXkEyXkFqcGdeQXVyNjY1MTg4Mzc@._V1_SX300.jpg', 'Ratings': [{'Source': 'Internet Movie Database', 'Value': '5.9/10'}], 'Metascore': 'N/A', 'imdbRating': '5.9', 'imdbVotes': '29', 'imdbID': 'tt0175546', 'Type': 'movie', 'DVD': '28 Sep 2017', 'BoxOffice': 'N/A', 'Production': 'N/A', 'Website': 'N/A', 'Response': 'True'}]

Вторая функция принимает в качестве входных данных список unique_keys и список json_responses. Создает словарь с именем movie_dict, где уникальные ключи — это ключи словаря, а значение — пустой список.

Использование вложенного цикла for для каждого объекта JSON и ключа movie_dictionary. Он извлекает значения из объекта JSON, где ключ объекта JSON соответствует ключу в movie_dict. Затем он добавляет значение объекта JSON в пустой список соответствующего ключа (метки) в movie_dict.

Всякий раз, когда movie_dict содержит ключ, которого нет в объекте JSON, для этого наблюдения возвращается значение None.

Наконец, после извлечения всех значений из каждого объекта JSON. Movie_dict преобразуется в DataFrame pandas.

def create_movie_df(
        keys, 
        list_jsons):
    
    #initiate empty dictionary that stores all unique keys
    movie_dict = {key:[] for key in keys}

    #Iterate through saved movie data and append data to corresponding key 
    for json in list_jsons: 
        
        #capture value if error return value = none
        for key in movie_dict:
            try:
                value = json[key]
            except KeyError:
                value = None

            #Append value to corresponding key in movie dict  
            movie_dict[key].append(value)

        #Transform dictionary to dataframe
        movie_df = pd.DataFrame.from_dict(
        movie_dict, 
        orient='columns')
        
    return movie_df

#Create movie df 
movie_df = create_movie_df(
    keys = unique_keys, 
    list_jsons=json_responses
    )

# return dimension of DataFrame
movie_df.shape

#Return first 100 rows
movie_df[0:100]

>>> movie_df = create_movie_df(
...     keys = unique_keys, 
...     list_jsons=json_responses
...     )
>>> movie_df.shape
(57377, 27)

>>> movie_df[0:100]
                      Awards  Year  ...   Type                      Director
0                        N/A  1995  ...  movie           S.A. Chandrashekhar
1                       None  None  ...   None                          None
2   21 wins & 24 nominations  2020  ...  movie            Georgis Grigorakis
3              4 nominations  2011  ...  movie                   Joseph Kahn
4                        N/A  1983  ...  movie             James Sbardellati
..                       ...   ...  ...    ...                           ...
95                       N/A  1978  ...  movie                   Walter Hill
96                      None  None  ...   None                          None
97                       N/A  1958  ...  movie                   Tara Harish
98   6 wins & 10 nominations  2021  ...  movie                      Ana Katz
99                    2 wins  2022  ...  movie  Reid Carolin, Channing Tatum

[100 rows x 27 columns]
>>>

Результатом является DataFrame, состоящий из 57377 строк данных фильма. В реальности это меньше, потому что на данном этапе данные еще не были очищены.

Источники:

  1. Авторы Википедии. (2023, 3 февраля). Скрапинг веб-страниц. Википедия. https://en.wikipedia.org/wiki/Web_scraping
  2. Что такое объектная модель документа? (без даты). https://www.w3.org/TR/WD-DOM/introduction.html#:~:text=The%20Document%20Object%20Model%20(DOM,document%20is%20доступен%20и%20манипулируется.)
  3. Офеда Дж., Боатенг Р. и Эффа Дж. (2019) Исследование интерфейса прикладного программирования (API), International Journal of Enterprise Information Systems, 15(3), стр. 76– 95. Доступно по адресу: https://doi.org/10.4018/ijeis.2019070105.
  4. Эхсан А., Абухалика М. а. ME, Родригес, Д., и Мишра, Д. (2022). Методологии тестирования RESTful API: обоснование, проблемы и направления решения. Applied Sciences, 12(9), 4369. https://doi.org/10.3390/app12094369
  5. OMDb API — открытая база данных фильмов. (н.д.). https://www.omdbapi.com/