Парсинг рекомендаций фильмов из IMDb

Парсим рекомендации фильмов быстро и без проблем

Метки:
  1. Support
    Сегодня утром за чашкой кофе я открыл Хабр и увидел там статью Визуализация данных для киноманов... Статья отличная, детально рассказывает, как решить поставленную задачу. Если вкратце, то там рассказывается о том, как спарсить "весь" Кинопоиск или IMDb и визуализировать полученные данные красивым графом. И мне показалось, что "в интернете кто-то не прав" (С). Ведь и вправду, автору потребовалось "2-3 дня" для сбора данных, а это непозволительно много, ведь, как известно, "время - деньги".

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

    Парсить будем IMDb, поэтому анализируем сайт. Начинать парсинг было решено со страниц рейтингов фильмов, и оттуда уже "углубляться". По каждому фильму нужно собрать название, дату, жанры, страны, режиссера и рекомендации (People who liked this also liked...). При визуализации данных рекомендации нужны будут для постоения связей, а нам они пригодятся во время парсинга для поиска новых фильмов. Т.е. нужно будет заходить в каждый рекомендованный фильм, получать вышеперечисленные данные, заходить в его рекомендации, и так далее, по кругу.

    Итак, теперь, когда определен алгоритм работы, составляем пресет. Используем Net::HTTP Net::HTTP - его будет достаточно. Сначала нам нужно из начальных списков получить ссылки на фильмы и подставить их в запросы. Т.к. это по сути разовое действие, то лучше парсинг ссылок сделать в шаблонизаторе, чтобы исключить лишнюю нагрузку во время парсинга. Подстановка на следующий уровень осуществляется с помощью инструмента tools.query.add().
    Код:
    [% IF query.lvl == 0;
        top = p1.data.match('<td class="titleColumn">[^<]+<a href="([^"?]+)', 1);
        FOREACH link IN top;
            tools.query.add('http://www.imdb.com' _ link);
        END;
    END %]
    Далее в пресете прописываем регулярные выражения для получения нужной информации. IMDb меняет язык в зависимости от заголовков браузера с которого он запрашивается. Поэтому, чтобы исключить ситуацию, когда результаты на разных языках (т.к. при парсинге будут использоваться прокси разных стран), смотрим в браузере, как IMDb определяет язык. И видим, что это Accept-Language. Поэтому прописываем этот заголовок в пресете:
    Код:
    Accept-Language:en-US,en;q=0.9
    Также, чтобы исключить возможные баны и ошибки, задаем Good status и Check content.

    Т.к. мы планируем выводить результат в JSON, то в Формате результата прописываем формирование нужной структуры данных. А также не забываем подставлять ссылки на рекомендации в запросы.
    Код:
        result = {};
        result.id = p1.id;
        result.name = p1.name.collapse;
        result.rating = p1.rating.remove('^none$');
        result.director = p1.director.remove('^none$');
        result.date = p1.date.remove('^none$');
        result.genres = [];
        FOREACH item IN p1.genres;
            result.genres.push(item.name);
        END;
        result.countries = [];
        FOREACH item IN p1.countries;
            result.countries.push(item.name);
        END;
        result.rec = [];
        FOREACH item IN p1.rec;
            result.rec.push(item.id);
            tools.query.add('http://www.imdb.com/title/' _ item.id _ '/');
        END;
    
        result.json _ ",\n";
    Обязательно включаем Уникализацию запросов, чтобы избежать повторных заходов на уже обработанные страницы.

    В целом на анализ сайта и составление пресета у меня ушло 20 мин. Плюс еще 10 минут на тесты и отладку. Итого за полчаса мы имеем готовый пресет. Запускаем в работу:)
    [​IMG]
    Как видно на скриншоте, парсинг запущен в 300 потоков. Средняя скорость более 2000 запросов в минуту.

    В итоге, спустя чуть менее, чем полтора часа была получена база результатов для 182 тысяч фильмов:
    [​IMG]

    Готовый пресет: https://a-parser.com/resources/268/
    Готовая база: https://files.a-parser.com/IMDB_base_feb-20_11-30-53.txt (46,9 Мб)
    venila и dankamaster нравится это.