Pull to refresh

Покорим Ruby вместе! Капля двенадцатая

Programming
Настало время писать на Руби что-то пригодное для использования ;) Сегодня мы научимся выдирать нужную нам информацию из web-страниц с помощью Руби на примере Хабра. Начнем с кармы.

open-uri


Давайте каждый откроет свою персональный Хаброцентр (ну или чужой, если все еще не обзавелись инвайтом ;) с адресом вида %username.habrahabr.ru. Наша задача – извлечь из полутысячи строк HTML-кода значение нашей кармы. Предполагаем, что для этого нам необходимо сохранить код страницы в файл, открыть и прочитать его и, используя регулярные выражения, получить необходимую информацию.

Библиотека open-uri сделает первую часть работы за нас. После включения ее в программу становится доступен метод open, который позволяет открывать как локальные файлы, так и URL:

require 'open-uri'
url = 'http://maxelc.habrahabr.ru/'
page = open(url)
text = page.read

open сохранит страницу в Tempfile, откуда мы прочитаем содержимое в строку text.

Используем регулярные выражения


Для того, чтобы выловить карму, составим регулярное выражение вида /НАЧАЛО(.*)КОНЕЦ/. Посмотрим на нужный нам кусок HTML-кода:
<span class="mark"><span>68,25</span><strong class="sign"></strong></span>

И вот несложное регулярное выражение готово:
%r{mark"><span>(.*)</span><strong class="sign">}m

Используем %r{}, чтобы забыть о правильности слэшей (очень удобно, в частности с HTML), m в конце строки говорит Руби искать совпадения на нескольких строках (в нашем случае это неважно, однако, опять же, весьма полезно в работе с HTML). Для поиска совпадений в строке будем использовать метод scan:
karma = text.scan(%r{mark"><span>(.*)</span><strong class="sign">})
puts "Karma = #{karma}"

Готово! Теперь вы можете добавить возможность вводить произвольный username, вывод хабрасилы, а также оформить все в ООП: выделить методы и классы.

hpricot


Достаточно удобно было бы парсить HTML, используя его же теги – ведь они замечательно структурируют информацию. В нашем примере достаточно узнать текст, заключенный в span, который в свою очередь заключен в span класса mark – и все, никаких сложных регулярных выражений. Однако тут есть одна нестыковка – не все документы имеют действительно валидный HTML, например, незакрытые и пропущенные теги. Чтобы решить проблему, достаточно перевести HTML в XML, четко структурированный формат, парсинг которого – обычная задача.

Hpricot – быстрый и удобный, основанный на С, HTML парсер, который как раз так и действует. Для парсинга XML используются библиотеки JQuery.
Устанавливаем: gem install hpricot. Начинаем кодить. Включаем hpricot в программу и загружаем URL, находим нужный элемент, заворачивая сразу все в ООП:
class Karma
require 'rubygems'
require 'hpricot'
require 'open-uri'

def initialize(name)
@url = "http:\/\/" + name + ".habrahabr.ru\/";
@hp = Hpricot(open(@url))
end

def
get
(@hp/"span.mark/span").inner_text
end
end

karma = Karma.new('maxelc')
puts "Karma = #{karma.get}"

Hpricot(open()) как раз преобразует HTML в XML и создает методы для переменной. @hp/"span.mark" – это шорткат от @hp.search("//span[@class='mark']"), означающий “ищи тэг <span class=’mark’>” (search в качестве параметра принимает выражение XPath или CSS). Метод inner_html получает содержание элемента (в случае HTML то, что заключено в тэги). Изменяя запрос, мы можем уходить во вложенные тэги, что мы и сделали: @hp/"span.mark/span”.

WWW::Mechanize


На сегодняшний день большая часть данных находится в “глубоком Вебе” – в базах данных, доступных через формы. Информация отсутствует в статичных страницах и генерируется налету, либо доступна только после только регистрации и аутентификации. В этот момент в игру вступает WWW::Mechanize.

Считать карму мы уже научились, а что делать, если мы хотим узнать, например, количество непрочитанных личных сообщений на хабре? Нам нужно пройти аутентификацию, получить cookies и только тогда выдернуть кол-во сообщений. Попробуем решить проблему максимально удобным способом!
Как всегда начнем с установки джема: gem install mechanize. Пишем код:
require 'rubygems'
require 'mechanize'
require 'hpricot'

agent = WWW::Mechanize.new # содержит инфу о куки, сессиях и др.
page = agent.get 'http://habrahabr.ru/login/'

form = page.forms.first # первая форма, которая встретится на странице
form.login = 'MaxElc' # см. атрибут name в HTML
form.password = '****'

page = agent.submit form # отправляем

a = agent.get('http://habrahabr.ru/').search(".//a[@href='http://maxelc.habrahabr.ru/mail/']").inner_text # сочетаем с hpricot
puts "У вас #{a}!"

Таким образом Mechanize позволяет нам заполнять формы, нажимать кнопки, ходить по ссылкам, имитируя браузер. Вместе с hpricot — опасная смесь ;)

Эпилог


Собственно, еще немного инфы — дальше будем смотреть другие библиотечки, практиковать их полезное использование. Жду отзывов!
Tags:rubyпарсерпрограммированиеучебникtutorial
Hubs: Programming
Total votes 47: ↑39 and ↓8 +31
Views17.1K

Popular right now

Top of the last 24 hours