Статьи

Обработка HTML с помощью Hpricot

В этом мире гибридных приложений Web2.0 и легкого доступа к API, очень приятно, как легко получать данные для сторонних сайтов и превращать их в нечто новое. К сожалению, не все были укушены этой ошибкой, поэтому нам, как разработчикам, иногда приходится немного больше работать, чтобы получить необходимую нам информацию. Распространенная техника называется скрэпом экрана, когда ваше приложение работает как браузер и анализирует HTML-код, возвращаемый сторонним сервером.

Хотя это должно быть достаточно просто, любой, кто когда-либо пытался сделать это, знает, как танцевать с регулярными выражениями в попытке найти нужные вам теги. К счастью, у нас, рубиновиков, есть библиотека Hpricot, которая берет на себя тяжелую работу по разбору HTML. Hpricot позволяет разработчикам получать доступ к html-элементам через CSS-селекторы и X-Path, так что вы можете легко ориентироваться на определенные теги. И поскольку он написан на C, он тоже довольно быстрый.

Установка

Hpricot — это драгоценный камень, поэтому его установка так же проста, как:

  гем установить hpricot 

Просто требуется библиотека в верхней части файла ruby:

require 'hpricot' 

использование

Давайте возьмем этот фрагмент HTML:

<html> <head> <title>Snippet</title> </head> <body> <div id="container"> <div id="navigation"> <ul> <li><a href="/">Home</a></li> <li><a href="/contact></a></li> </ul> </div> <div id="sub-content"> <p>This would be some sort of sidebar</p> </div> <div id="content"> <p>This is paragraph 1</p> <p>This is paragraph 2</p> </div> </div> </body> </html>
<html> <head> <title>Snippet</title> </head> <body> <div id="container"> <div id="navigation"> <ul> <li><a href="/">Home</a></li> <li><a href="/contact></a></li> </ul> </div> <div id="sub-content"> <p>This would be some sort of sidebar</p> </div> <div id="content"> <p>This is paragraph 1</p> <p>This is paragraph 2</p> </div> </div> </body> </html> 

Делая это, мы можем легко извлечь содержимое абзацев (предположим, что HTML уже хранится в переменной @html).

doc = Hpricot(@html) pars = Array.new doc.search("div[@id=content]/p").each do |p| pars << p.inner_html end
doc = Hpricot(@html) pars = Array.new doc.search("div[@id=content]/p").each do |p| pars << p.inner_html end 

Да, вот и все. Теперь у вас есть массив с двумя элементами, которые совпадают с копией в двух тегах p. Заметьте, что тег p в элементе sub-content не извлекается?

Однако на этом все не заканчивается, вы также можете манипулировать HTML — что может пригодиться, если вы хотите, скажем, создать быструю и грязную мобильную версию. Допустим, мы хотели удалить под-контент div из мобильной версии, мы могли бы сделать это:

doc = Hpricot(@html) doc.search("div[@id=sub-content]").remove puts doc
doc = Hpricot(@html) doc.search("div[@id=sub-content]").remove puts doc 

Результирующий HTML больше не имеет div, называемый суб-контентом!

Добавить новый класс в навигацию ul так же просто, как:

doc = Hpricot(@html) doc.search("div[@id=navigation]/ul").set("class", "nav")
doc = Hpricot(@html) doc.search("div[@id=navigation]/ul").set("class", "nav") 

Это только вершина айсберга — библиотека действительно мощная и простая в использовании. Зайдите на официальную страницу для более (менее тривиальных) примеров.

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