× Темы

Парсинг nokogiri ruby

+1

Парсинг nokogiri ruby

Web Scraping with Ruby
Вольный перевод

В статье рассматривается простой парсер новостей, с помощью библиотеки nokogiri методом через CSS-Селекторы.

Парсинг веб-приложения с использованием языка Ruby - это легче, чем вы можете подумать. Начнем с простого примера, цель получить отформатированный в формате JSON массив объектов, которые будут использованы для локального кинотеатра.

Первым делом нужно определить путь для загрузки html страницы. В Ruby для этой цели реализован Net::HTTP, его использует библиотека open-uri, ей мы воспользуемся для получения кода нашей страницы.

Итак первым делом html грабинга мы сделаем запрос на удаленный сервер.


require 'open-uri'

url = 'http://www.cubecinema.com/programme'
html = open(url)


Отлично, мы получили код страницы, теперь приступим к поиску информации. Для этого существует gem Nokogiri. Сейчас мы создадим новый Nokogiri экземпляр, который получит наш код.

require 'nokogiri'

doc = Nokogiri::HTML(html)


Использовать nokogiri это здоровою Мы можем делать поиск информации с помощью CSS-селекторов, что очень удобно, также можно делать поиск с помощью xpath.

Хорошо теперь у нас есть документ который внутри себя содержит список фильмов. Каждая html структура имеет похожий вид, пример:

<div class="showing" id="event_7557">
  <a href="/programme/event/live-stand-up-monty-python-and-the-holy-grail,7557/">
    <img src="/media/diary/thumbnails/montypython2_1.png.500x300_q85_background-%23FFFFFF_crop-smart.jpg" alt="Picture for event Live stand up + Monty Python and the Holy Grail">
  </a>
  <span class="tags"><a href="/programme/view/comedy/" class="tag_comedy">comedy</a> <a href="/programme/view/dvd/" class="tag_dvd">dvd</a> <a href="/programme/view/film/" class="tag_film">film</a> </span>
  <h1>
    <a href="/programme/event/live-stand-up-monty-python-and-the-holy-grail,7557/">
      <span class="pre_title">Comedy Combo presents</span>
      Live stand up + Monty Python and the Holy Grail
      <span class="post_title">Rare screening from 35mm!</span>
    </a>
  </h1>
  <div class="event_details">
    <p class="start_and_pricing">
      Sat 20 December | 19:30
      <br>
    </p>
    <p class="copy">Brave (and not so brave) Knights of the Round Table! Gain shelter from the vicious chicken of Bristol as we gather to bear witness to this 100% factually accurate retelling ... [<a class="more" href="/programme/event/live-stand-up-monty-python-and-the-holy-grail,7557/">more...</a>]</p>
  </div>
</div>



Обработка html

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

showings = doc.css('.showing').map do |showing|
  showing_id = showing['id'].split('_').last.to_i
  
  tags = showing.css('.tags a')
         .map{|tag| tag.text.strip}
  
  title_el = showing.at_css('h1 a')
             .children
             .delete_if{|c| c.name == 'span'}
  
  title = title_el.text.strip
  
  dates = showing.at_css('.start_and_pricing')
          .inner_html
          .strip
          .split('<br>')
          .map(&:strip)
          .map{|d| DateTime.parse(d)}
  
  description = showing.at_css('.copy')
                .text
                .delete('[more...]')
                .strip
  
  {id:          showing_id,
   title:       title,
   tags:        tags,
   dates:       dates,
   description: description}
end

примечание: Спасибо за ревью кода Антону Городишенину.

Рассмотрим, что делает каждая строка

showing_id = showing['id'].split('_').last.to_i

Первым делом получаем уникальный идентификатор нашей новости, которая выступает в качестве атрибута id в html разметке.
Используем опцию ``showing['id']`` которая вернет нам "event_7557". Мы заинтересованы только в целочисленном идентификаторе, так что мы разделим полученную строку используя знак подчеркивания на массив .split('_') и затем возьмем последний элемент из массива и преобразуем его в тип integer .last.to_i

tags = showing.css('.tags a').map { |tag| tag.text.strip }

Здесь мы находим все теги в нашем объекте, используя ``.css`` метод, который возвращает массив совпадающих элементов. Далее для каждого элемента с помощью метода .strip убираем пустое пространство . К примеру код выше вернет ["comedy", "dvd", "film"]


title_el = showing.at_css('h1 a')
title_el.children.each { |c| c.remove if c.name == 'span' }
title = title_el.text.strip


Здесь мы получаем заголовок для первого элемента at_css, который находиться в селекторе h1 > a. Затем для каждого вложенного селектора удаляем, те что имеют имя span. Вытаскиваем из нашей ссылки текст и убираем лишние пробелы.

dates = showing.at_css('.start_and_pricing').inner_html.strip
dates = dates.split('<br>').map(&:strip).map { |d| DateTime.parse(d) }


Далее код для получения даты и времени показа. Здесь немного сложнее, потому что фильмы могут показывать несколько дней и, иногда, цена может быть в этом же элементе. Мы мапим даты, которые найдем с помощью DateTime.parse и в результате получаем массив Ruby объектов — DateTime.

description = showing.at_css('.copy').text.gsub('[more...]', '').strip

Получаем описание, где удаляем ``[more...]`` используя метод .gsub


showings.push(
    id: showing_id,
    title: title,
    tags: tags,
    dates: dates,
    description: description
  )

Записываем полученные значения в массив.


Теперь для вывода найденной информации конвертируем в JSON

Для этого добавим в код

require 'json'

puts JSON.pretty_generate(showings)
все для dleфильмы и сериалы онлайн hdавтоматический обмен webmoney на приват24android игры, приложения, инструкции, обзоры



Оценить статью