Цель этой статьи

Эта статья будет руководством по проекту Data Science для начинающих; изучение основ веб-скрейпинга, исследовательского анализа данных (EDA) и обучения машинному обучению (линейная регрессия) для 250 лучших фильмов IMDb. Новички в науке о данных являются основной аудиторией, хотя ожидается, что опытные ученые также могут использовать руководство, чтобы вспомнить и освежить свои знания по предмету.

Из-за моего опыта и интереса к науке и программированию я думаю, что наука о данных идеально подходит для меня. Но я долго не знал, с чего начать, знал, что должен сделать проект, но не знал, как его сделать. Мне еще предстоит многому научиться, но это приключение, в котором, со своими взлетами и падениями, опыт, который можно получить на этом пути, велик и обилен; несмотря на обилие, иногда может быть сложно узнать более одной вещи из нескольких источников одновременно. По этой причине в этой статье мы узнаем, как создать простой проект по науке о данных.

Веб-скрейпинг

Прежде всего, давайте импортируем наши необходимые библиотеки.

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

Ради этого давайте возьмем наши данные из списка 250 лучших фильмов IMDb. Поэтому мы вызываем нашу функцию getAndParseURL() сверху, ищем и получаем ссылку на каждый фильм и помещаем их в список.

Важно, чтобы мы понимали, что делает этот код, поэтому давайте разберем и посмотрим, что происходит в нашем цикле for.

Сначала посмотрим, что возвращает наша переменная soup .

<!DOCTYPE html>

<html xmlns:fb="http://www.facebook.com/2008/fbml" xmlns:og="http://ogp.me/ns#">
<head>
<script type="text/javascript">var ue_t0=ue_t0||+new Date();</script>
<script type="text/javascript">
window.ue_ihb = (window.ue_ihb || window.ueinit || 0) + 1;
if (window.ue_ihb === 1) {

var ue_csm = window,
    ue_hob = +new Date();
(function(d){var e=d.ue=d.ue||{},f=Date.now||function(){return+new Date};e.d=function(b){return f()-(b?0:d.ue_t0)};e.stub=function(b,a){if(!b[a]){var c=[];b[a]=function(){c.push([c.slice.call(arguments),e.d(),d.ue_id])};b[a].replay=function(b){for(var a;a=c.shift();)b(a[0],a[1],a[2])};b[a].isStub=1}};e.exec=function(b,a){return function(){try{return b.apply(this,arguments)}catch(c){ueLogError(c,{attribution:a||"undefined",logLevel:"WARN"})}}}})(ue_csm);

- Подождите... позвольте мне остановить вас прямо здесь... Он просто печатает весь HTML-код веб-сайта!

Так как же мы собираемся найти что-нибудь во всем этом беспорядке? Мы собираемся использовать теги, которые указывают, куда мы хотим перейти в нашем HTML-тексте. Итак, давайте проверим, где вложен наш первый фильм. Просто щелкните правой кнопкой мыши и выберите Проверить, чтобы найти то, что вы ищете. В нашем случае мы хотим найти URL первого фильма.

Взглянув на наш HTML-текст, мы увидим, что есть только один тег tbody (или, по крайней мере, то, что мы ищем, — это первый тег tbody в нашем HTML-код). Таким образом, если мы запустим soup.tbody, он напечатает только тот тег tbody, для которого мы его указали.
(Примечание. Если было больше tbody ниже, soup.tbody вернет только первый)

Нам нужно, чтобы наш HTML-текст был структурирован таким образом, что все наши фильмы помещаются в большой тег tbody , а после него идет по одному тегу tr на каждый элемент. фильм. Если бы мы запустили soup.tbody.tr, это напечатало бы первый в истории фильм, но мы хотим запустить цикл for, чтобы получить каждый фильм в списке. Вот что делает наша 4-я линия. Он входит в soup.tbody и затем находит все теги tr; soup.tbody.findAll(‘tr’) и возвращает список, в котором каждый тег tr является элементом.

После того, как мы попадем внутрь каждого тега tr, мы найдем второй тег td(поскольку он возвращает список, мы берем [1 ] item), потому что именно туда вложена ссылка на наш фильм, тогда мы можем использовать еще один тег a,, чтобы, наконец, добраться до ссылки, которая приведет нас на исходную страницу фильма! Таким образом, мы добавляем каждый существующий href в наш тег a и захлопываем https://www.imdb.com/, прежде чем сохранить в наш список movie_urls.

Итак, наш список movie_urls выглядит так.

['https://www.imdb.com/title/tt0111161/',
 'https://www.imdb.com/title/tt0068646/',
 'https://www.imdb.com/title/tt0071562/',
 'https://www.imdb.com/title/tt0468569/',
 'https://www.imdb.com/title/tt0050083/',
...]

Теперь, когда мы взяли URL каждого фильма из нашего списка, давайте зайдем на страницу каждого фильма, засучим рукава и очистим наши данные. Самое приятное то, что нам просто нужно сделать это для одного фильма и повторить это через наш список, чтобы заставить python делать это для каждого фильма!

Это будет самая захватывающая часть веб-скрейпинга, когда мы пытаемся буквально очистить наши данные, встроенные в веб-страницу. Итак, мы помещаем наш список movie_urls в цикл for, чтобы получить каждый элемент и передать его нашей функции getAndParseURL() для каждого фильма в списке. Давайте посмотрим на первый и самый простой парсинг, который является названием наших фильмов.

Как и в случае с soup.tbody, который эквивалентен soup.find(‘tbody’), мы хотим указать, какой тег мы на самом деле ищем. Поскольку в этом HTML-тексте может быть много тегов h1; нам нужно искать с помощью атрибута, который уникален только для нужного нам раздела, в котором хранятся наши данные.

Есть некоторые атрибуты, которые мы могли бы использовать, такие как class или, может быть, textlength, но некоторый другой текст также может иметь такую ​​же textlength, и этот конкретный class «TitleHeader__TitleText-sc-1wu6n3d-0 gxLYZW» уникально только для этого конкретного фильма. Таким образом, мы не можем получить название другого фильма с помощью этого атрибута. К счастью, IMDb помогает нам в этом и дает тегу h1 атрибут data-testid, который мы можем легко использовать для каждого фильма в нашем списке!

html.find('tag', {"key of the attribute":"value of the attribute"}

So;

html.find('h1', {"data-testid":"hero-title-block__title"}).text
(Note: .text is there to get the string value in the h1 tag which is the title of the movie)

На самом деле нет простого способа объяснить эти вещи, вам просто нужно копаться и исследовать это самостоятельно.

Давайте посмотрим на более сложный пример, который представляет собой количество голосов для оценок. Сложность заключается в том, что они представляют информацию в аббревиатуре. Например, если у фильма 1 700 000 голосов, он дается нам как «1,7 млн». Так что мы должны пройти лишнюю милю и лишить М и умножить на 1 000 000 в качестве компенсации. Но что, если у него не миллионы голосов, а, скажем, 1000 голосов; в этом случае он будет написан как «1K», и если у него нет ни миллиона, ни тысячи голосов, мы можем принять значение как есть.

if 'M' in votes:
    votes = int(float(votes.split('M')[0])*1_000_000)                                     elif 'K' in votes:
    votes = int(float(votes.split('K')[0])*1_000)                                     else:
    votes = int(votes)

Этот код можно было бы написать лучше, но его основная цель — дать представление о том, как можно спроектировать процесс.

Что касается того, как мы вообще получили данные о голосовании; мы использовали серию тегов, чтобы добраться до пункта назначения. Как мы видим ниже, сначала идет тег div с атрибутом data-testid, затем идет тег ссылки a, после чего мы есть два тега div вплотную, которые содержат еще три тега div внутри, и мы должны взять второй (элемент списка [1]) div и внутри этого есть есть еще три тега div, и наши данные находятся в третьем (как в элементе списка [2]), а затем получают его значение, как с .text, поэтому;

html.find('div', {"data-testid":"ero-rating-bar__aggregate-rating"})
.a.div.div.findAll('div')[1].findAll('div')[2].text

Этот процесс может быть выполнен для очистки всех данных, которые вы видите на веб-странице. И мы бросаем try: и except: здесь и там, чтобы наш анализ не прерывался только потому, что для фильма не были предоставлены данные о бюджете (я говорю вам Бабам ве Оглум!).

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

А теперь давайте взглянем на наш красивый фрейм данных!

dfMovies.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 250 entries, 0 to 249
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype         
---  ------       --------------  -----         
 0   Title        250 non-null    object        
 1   Revenues     241 non-null    float64       
 2   Budget       222 non-null    float64       
 3   Runtime      250 non-null    object        
 4   Certificate  250 non-null    object        
 5   ReleaseDate  250 non-null    datetime64[ns]
 6   Score        250 non-null    int64         
 7   Votes        250 non-null    int64         
 8   Directors    250 non-null    object        
 9   Writers      250 non-null    object        
 10  Stars        250 non-null    object        
 11  Genres       250 non-null    object        
dtypes: datetime64[ns](1), float64(2), int64(2), object(7)
memory usage: 23.6+ KB

На этом мы завершаем часть веб-скрейпинга нашего проекта.

Исследовательский анализ данных

Вскоре.

Моделирование

~

Полученные результаты

~

Заключение

~