07.04.2024: Эта статья изначально была опубликована на habr.com и была просмотрена там 66 тысяч раз. Но теперь я решил перенести её в свой блог.
От переводчика: Оригинал статьи Web Scraping with Ruby
Обзор
Это перевод статьи которую я нашел полезной при изучении языка программирования Ruby. Парсинг меня интересует в личных целях. Мне кажется, это не только полезный навык, но и хороший способ изучить язык.
Парсинг веба на Ruby легче, чем вы можете думать. Давайте начнем с простого примера: я хочу получить красиво отформатированный JSON массив объектов, представляющий список фильмов с сайта местного независимого кинотеатра.
В начале нам нужен способ скачать html страницу, которая содержит все объявления о фильмах. В Ruby есть встроенный http клиент, Net::HTTP
, а также надстройка над ним - open-uri
.
Open-uri хорош для базовых вещей, вроде тех, что мы делаем в уроке, но у него есть некоторые проблемы, поэтому, возможно, вы захотите найти другой http клиент для продакшн среды.
Итак, первая вещь, которую надо сделать - это скачать html с удаленного сервера.
Отлично, теперь у нас есть страница, которую мы хотим парсить, теперь нам нужно вытащить некоторую информацию из нее. Лучший инструмент для этого - Nokogiri. Мы создаем новый экземпляр Nokogiri для нашего html, который мы только что скачали.
Nokogiri крут, потому что позволяет обращаться к html используя CSS селекторы, что, на мой взгляд, гораздо удобнее чем использовать xpath.
Ок, теперь у нас есть документ, из которого мы можем вытащить список кинофильмов. Каждый элемент списка имеет такую html структуру, как показано ниже.
Обработка html
Каждый фильм имеет css класс .showing
, так что мы можем выбрать все шоу и обработать их по очереди.
Давайте разберем по частям код, представленный выше.
В начале мы берем уникальный идентификатор id, который любезно выставлен как атрибут html идентификатора в разметке. Используя квадратные скобки, мы можем получить доступ к атрибутам элементов. Таким образом, в случае html, представленного выше, showing['id']
должен быть “event_7557”. Нам интересен только числовой идентификатор, так что мы разделяем результат с помощью подчеркивания .split('_')
и затем берем последний элемент из получившегося массива и конвертируем в целочисленный формат .last.to_i
.
Здесь мы находим все теги для фильма, используя .css
метод, который возвращает массив совпадающих элементов. Затем мы мапим (применяем метод map) элементы, берем из них текст и убираем в нем пробелы. Для нашего html результат будет ["comedy", "dvd", "film"]
.
Код для получения заголовка немного сложнее, потому что этот элемент в html содержит некоторые добавочные span элементы с префиксами и суффиксами. Мы берем заголовок, используя .at_css
, который возвращает один соответствующий элемент. Затем мы перебираем каждого потомка заголовка и удаляем лишние span. В конце, когда span убраны мы получаем текст заголовка и чистим его от лишних пробелов.
Далее код для получения даты и времени показа. Здесь немного сложнее, потому что фильмы могут показывать несколько дней и, иногда, цена может быть в этом же элементе. Мы мапим даты, которые найдем с помощью DateTime.parse
и в результате получаем массив Ruby объектов - DateTime
.
Получение описания довольно простой процесс, единственное что стоит сделать, это убрать текст [more...]
используя .gsub
Теперь, имея все необходимые части в переменных, мы можем записать их в наш хеш (hash), созданный для отображения всех фильмов.
Вывод в JSON
Теперь, когда у нас отбирается каждый фильм и мы их массив, можем конвертировать результат в формат JSON.
Данный код выводит массив showings перекодированный в формат JSON, при запуске скрипта вывод можно перенаправить в файл или другую программу для дальнейшей обработки.
Собираем все вместе
Собрав все части в одном месте, мы получаем полную версию нашего скрипта:
Если сохранить это в файл, например, scraper.rb
и запустить ruby scraper.rb
, то вы должны увидеть вывод в формате JSON. Он должен быть похож на то, что представлено ниже.
Всё. И это всего лишь базовый пример парсинга. Сложнее парсить сайт, который требует в начале авторизоваться. Для таких случаев я рекомендую посмотреть в сторону mechanize, который работает над Nokogiri.
Надеюсь, данное введение в парсинг даст вам идеи о данных, которые вы хотите видеть в более структурированном формате, используя методы, описанные выше.
Также я планирую перевести другую статью на тему парсинга от этого же автора.
Все статьи серии:
- Веб-парсинг на Ruby (вы здесь)
- Продвинутый парсинг веб-сайтов с Mechanize
- Использование morph.io для веб-парсинга