Микроформаты — это хорошо, просто и понятно.
Как можно извлечь микроформатированный контент из документа и сделать с ним миллион классных штук?
XSLT
Удобно для запросов в XML-документе на извлечение микроформатированного контента использовать выражения XPath.
Вот пример «ручной» работы с XHTML-документом, содержащим μf:
Пример работы с XPath
(Требуется утилита xmllint из пакета libxml).
Запрашиваем страницу:
$ wget dzhus.org/author
Открываем XML-консоль:
$ xmllint --shell index.html
Устанавливаем префикс пространства имён, чтобы были видны XHTML-элементы:
/ > setns xhtml=http://www.w3.org/1999/xhtml
Запрашиваем элемент с именем класса «vcard» (вернёт все hCard на странице):
/ > xpath //xhtml:*[@class='vcard'] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT div ATTRIBUTE id TEXT content=owner-vcard ATTRIBUTE class TEXT content=vcard
Или из всех hCard на странице выбираем ссылки, у которых установлен
XFN-аттрибут rel="me":
/ > xpath //xhtml:*[@class='vcard']/xhtml:a[@rel='me'] Object is a Node Set : Set contains 1 nodes: 1 ELEMENT a ATTRIBUTE class TEXT content=url ATTRIBUTE rel TEXT content=me ATTRIBUTE href TEXT content=http://dzhus.org ATTRIBUTE title TEXT content=#D0#9B#D0#B8#D1#87#D0#BD#D1#8B#D0#B9 #D1#81#D0#B0#D0#B9#D1#82
В реальных задачах по извлечению μf применимы преобразования XML при помощи XSLT. В XSLT можно извлекать данные из исходного XML-документа с применением выражений XPath.
Использование XSLT позволяет разделить логику программной обработки страниц и непосредственно извлечение/форматирование данных, позволяет использовать одни и теже механизмы извлечения в разных программах на разных языках. Кроме того, XSLT просто ближе к предметной области, чем явное кодирование разбора XML-дерева в тексте обрабатывающей программы, ИМХО. Синтаксис выражений XPath также скрывает детали реализации сложной фильтрации и выборки элементов из XML.
Недостатком XSLT является достаточно громоздкий синтаксис (в общем случае это пипец полный, но увы — XML =).
Идея оказалась не нова; уже существуют некоторые основанные на XSLT средства преобразования микроформатированных данных из страниц.
Микроформаты, GRDDL и Семантическая Паутина
Поскольку микроформаты — маленький промежуточный шаг на пути к Semantic Web, по-хорошему нужно использовать GRDDL — специальный механизм обозначения RDF-совместимых данных в XML-документе, а при помощи GRDDL однообразно извлекать микроформатированный контент. Возможно, GRDDL обеспечит тот будущий великий перенос данных на сверхвысокий уровень представления, к которому сейчас готовятся многие люди, маленькими шажками (например, используя микроформаты) увеличивая «семантичность» данных. На страницах w3.org предлагается интересный обзор возможных случаев использования GRDDL.
С RDF-данными можно работать на гораздо более высоком уровне, применяя специальные языки запросов. По сравнению с возможностями RDF-технологий копание в коде веб-страниц при помощи XSLT выглядит минимум суетливо.
На землю
Semantic Web — конечно великая цель и очень хорошо, но большинство двуногих обезьян, создающих страницы для Сети не могут написать даже well-formed документ (не говоря уже о валидности), чтобы хоть как-то упростить жизнь создателям средств обработки данных. Так что бок о бок с XML-парсерами существуют «real-world» парсеры даже не HTML, а чего-то непонятного (часто это деликатно называется Tag Soup, на самом деле это обычно блевота из тэгов), которые пытаются разобрать и угадать как можно больше из того некорректного кода, который часто встречается в Интернете, как это делают браузеры. Эвристика, болото частных случаев и попытка заочно вправить мозги задним числом верстальщикам — в итоге не всегда устойчивый результат и непрозрачная логика.
Тем не менее, я представлю простой пример основанного на XSLT обработчика распределённых социальных сетей, основанных на XFN. Во время обработки буду также учитывать rel-tag.
Реализация
Инструменты
В libxml есть возможности «восстановления» «повреждённого» кода с веб-страниц. Там всё равно достаточно строгий парсер, хотя с включённым восстановлением удаётся увеличить количество разбираемых страниц в несколько раз. Тем не менее, не удаётся разобрать до 35% процентов веб-страниц. Было бы удобно, однако, использовать libxml, поскольку в ней также очень быстрый XSLT-процессор.
Tidy — то, что нужно. Tidy позволяет с большой долей успеха формировать из побитых веб-страничек валидные XHTML-документы.
Для извлечения микроформатированного контента будет использоваться простой стилевой файл XSL.
Принцип работы
В принципе, схема рекурсивной обработки XFN должна быть уже очевидна. Программа будет принимать пару параметров — URL «точки входа» и глубину обработки. Страница, запрошенная по переданному в качестве параметра URL, будет обработана Tidy и разобрана парсером libxml, после чего на неё будет наложено XSL-преобразование. Предлагается в качестве результата обработки каждой страницы использовать промежуточный XML-формат, простой и удобный для последующей обработки.
XSL-преобразование, применяемое к каждой странице, будет извлекать интересующий микроформатированный контент, в числе которого будут размеченные с учётом XFN ссылки. Список этих ссылок составит новый набор страниц для обработки, к каждой из которых вся схема будет применена аналогично. Таким образом, используется тип рекурсивной обработки «в глубину» (а не «в ширину»).
На каждом шаге обработки будет проверяться текущая «глубина» (то, насколько в работе программа ушла от «нулевого уровня» — самой первой страницы). При достижении максимально допустимой глубины уже не будет производиться поиск новых страниц для обработки.
Страницы, находящиеся сразу за самым глубоким уровнем, однако, всё равно
будут запрошены и обработаны, но по упрощённой схеме: будет извлечён
лишь заголовок страницы. Это очень расточительно (запрос, обработка
страницы лишь для извлечения значения <title></title>!), но в таком
случае будет известен заголовок каждой страницы, на которую ссылается
любая другая в обрабатываемой сети. Это очень полезно для генерации
карты сети по результатам работы программы (если бы не запрашивались
заголовки страниц на «границе» обработки, пришлось бы в качестве
названий узлов на границе карты использовать их URL — в большом
количестве выглядит убого и сильно мешает восприятию; впрочем, заголовки
страниц в качестве меток — тоже громоздко).
Результатом работы предполагается XML-файл со списком обработанных страниц. В каждом элементе будут содержаться приемлемо организованные извлечённые микроформатированные данные.
Он, в свою очередь, подлежить дальнейшей обработке с целью получения более осязаемых результатов.
Рабочий пример
Пример исходников доступен по адресу http://github.com/dzhus/xfn-spider (лучше брать самую последнюю ревизию):
-
mf-extract.xsl и mf-extract-bottom.xsl — пара простых стилей для извлечения µf.
mf-extract-bottom.xslприменяется к страницам, которые находятся на уровне глубины обработки после максимального и извлекает только заголовок. -
get-urls.xsl накладывается на результат работы
mf-extract.xslи формирует список URLов для последующей обработки -
postprocess.xsl мочит дубликаты с разными URL-ами, но одинаковыми заголовками страницы. Достаточно успешно.
-
xfn-spider.py — пример обёртки на Python вышеупомянутых четырёх стилей. Думаю, что исходник вполне понятен, и его можно легко перенести на другой язык (включая enterprise-level языки типа whitespace).
Работает так:
$ python xfn-spider.py http://entry-point.com 5 > output.xml
Отладочные сообщения выводятся на stderr и не попадают в output.xml.
Можно добавлять дополнительные действия по извлечению контента на уровне XSL-преобразований, не меняя Python-обёртку: механизм отделён от политики.
Пояснения также есть в файлах README и TODO.
Что делать дальше
Полученный в результате работы output.xml — бесполезный полуфабрикат.
Можно сделать с ним что-нибудь прикольное.
Например, визуализировать.
Many eyes
Many eyes — инициатива IBM по созданию общественного ресурса по обмену статистическими данными и предоставлению средств визуализации этих данных. Короче говоря, можно туда загрузить свой dataset и визуализировать его. Возможностей в тысячу раз меньше, чем у нормальных средств визуализации (R, OpenDX или ROOT), но в Many Eyes дан упор на общественность процесса и «collaborating». И ещё там везде Java. Корпорэйты, что с них взять.
Карта XFN
Мне приглянулась имеющаяся там визуализация «Network»: более-менее нормальные картинки, сглаживание, красивая подсветка и всё такое. На входе для визухи сети нужен список пар — соединённых узлов, типа:
Петя Вася
Коля Вася
Вася Настя
Петя Настя\
Колонки разделены символом табуляции.
Из полученного в результате работы xfn-spider.py XML-я такой набор пар
несложно получить ещё одним XSL-преобразованием (лежит в репо под именем
make-manyeyes-network.xsl):
$ xsltproc make-manyeyes-network.xsl output.xml > many-eyes.txt $ cat many-eyes.txt
Полученный набор данных можно загрузить на Many Eyes и получить интерактивненькую карту XFN (Челик сказал «woha»):
(Эта визуализация очень неполная и была получена на начальном этапе работы над описываемыми инструментами; в реальности узлов гораздо больше.)
Минус — тип связей никак не используется (впрочем, при большом количестве узлов разноцветные рёбра читаются ещё хуже просто чёрных).
Облако тэгов на всю XFN
Помимо XFN-ссылок извлекались также и размеченные при помощи rel-tag тэги на сайтах. Можно из результирующего XML просто дёрнуть их список и получить облако тэгов (HEY LOOK I'M WEB 2.0!).
Пусть у меня есть output.xml — результат xfn-spider.py. Тэги можно
вырезать и простым грепом, но я снова хочу использовать Many Eyes и
визуализацию [«Tag Cloud»][], для неё лучше подготовить не просто список
тэгов, а пары «тэг — количество упоминаний». Для этого снова можно
применить совсем примитивное XSL-преобразование
[make-manyeyes-tags.xsl][]:
$ xsltproc make-manyeyes-tags.xsl output.xml > tags.txt $ cat tags.txt craig ferguson 1 cryotherapy 1 cryptography 2 culture 2 danny hillis 1 data mining 1 data web 2 data-web 4
Используя такой набор данных, можно получить подобное «облако»:
[![][1] ![misc][]][]
Graphviz
Рисовать сети на Many Eyes — забавно, но есть [Graphviz][] — славный набор средств для качественной отрисовки графов. Можно преобразовывать описание XFN в формат DOT, который принимают программы Graphviz. Это имеет смысл при обработке особо больших сетей (на глубину >20), а то, скажем апплет Many Eyes может поперхнуться таким количеством узлов в сети.
Создание файла OPML со списком лент XFN
Тут тоже всё понятно. На большинстве сайтов уважают [RSS][] и в коде есть указание на RSS-ленту:
При обработке XFN нужно выжимать из страниц как можно больше информации, если она удобно размечена.
Есть [OPML][] — достаточно широко используемый XML-формат для обмена структурированными списками. Часто применяется для импорта/экспорта списков RSS/Atom-лент и обмена списками лент между разными RSS-читалками.
Так вот, выгодно при обработке сети заодно для каждого сайта сохранять ссылку на его RSS-представление, потом из списка RSS-представлений генерить файл OPML (или другого формата), чтобы потом его использовать для импорта в любимой RSS-читалке (например, [Google Reader][]) и читать всю тусовку!
[make-opml.xsl][] does the job:
$ xsltproc make-opml.xsl output.xml > feeds.opml
После чего feeds.opml можно импортировать прямиком в RSS-ридер.
Однажды собрав список лент и получив доступ к «синдицированному» контенту, можно тоже отслеживать всякие тренды и подбивать статистику по всей XFN.
Недостаткомъ подхода является то, что не все ставят ссылку на
RSS-представление в надлежащее место — тэг <link>.
Если во время обработки XFN не просто собирать XFN-ссылки, но ещё и извлекать размеченные при помощи OPML блогроллы (понятно, что список XFN-ссылок на друзей и просто блогроллы не всегда совпадают) — toodoo.ru становится ненужным :)
Обработка социальных сетей
Однажды я поставил обработку на глубину 30, но через десять минут понял, что такого количества трафика у меня нет: уже на третьем уровне паучок вышел на чей-то профиль в [twitter.com][], а там на каждой странице участника список друзей размечен при помощи XFN и модно иметь по 30 «друзей» :) В общем, через час просто надоело ждать :- Как-то странно вышло, до этого при тестировании робот не выходил на Twitter-овские связи. Quick googling показало, что как раз в этот день на Twitter внедрили [микроформаты][2]
Так что визухи, ссылки на которые были выше — весьма неполные :)
Ясно что уже 30³ — это 27000 и до фига трафика и времени. Так что социальные сети обрабатывать стоит с осторожностью и, похоже, XFN-ссылки — не лучший способ для этого (слишком ресурсоёмко).
В общем, обработка XFN с точкой входа на том же [http://tantek.com][] на глубину хотя бы 7 — задача явно не для PC, причём именно из-за того, что робот выходит в Twitter, где сверхплотные и сверхгустые XFN-связи.
Вот, что мне удалось в итоге получить (глубина всего лишь 3):
[![Many Eyes visualization][] ![misc][misc image]][]
Недостатки использования XSLT
Fucking slow! Задержки сети при получении всей страницы — огромные! Обработки сети с глубиной 10 — дело многих минут. Основные проблемы — когда попадается особо тормозной хост, запрос страницы с которого идёт чуть ли не десять секунд. Сам парсинг занимает очень мало времени. В данном случае выгодно держать на каждом что-то типа кэша, как в [XFN crawler][], но это убивает соль микроформатов — простоту добавления и редактирования, и это лишний связующий уровень, снижающий прозрачность технологии.
Есть баги, связанные с обработкой разных ссылок на одни и те же ресурсы.
Это просто сложно фильтровать. Я применил такую политику: из группы
страниц с одинаковыми заголовками выбирается та, у которой больше всего
связей. Она остаётся в результирующем файле без изменений. Все остальные
лишаются списка тэгов и списка связей, для них остаются только
заголовки. В итоге получается достаточно разумно и почти ничего не
ломается. Фильтрация происходит на уровне postprocess.xsl. Отладка
обработки затрудняется значительными временными затратами на извлечение
данных.
Стандартная отмазка от автора
(афтара?)
Я не знаю XSLT — в стилях есть ужасные места (например, обработку XFN-ссылок, возможно, было бы проще сделать с использованием регулярных выражений из EXSLT; текущий вариант создан под воздействием [grokXFN.xsl][] — стиля для преобразования XFN в FOAF).
{#blogThisImgSmall} [misc image]: http://services.alphaworks.ibm.com/manyeyes/images2/blog_this_caption.jpg {#Any_14} [«Tag Cloud»]: http://services.alphaworks.ibm.com/manyeyes/page/Tag_Cloud.html [make-manyeyes-tags.xsl]: http://github.com/dzhus/xfn-spider/blob/master/make-manyeyes-tags.xsl [1]: http://services.alphaworks.ibm.com/manyeyes/static-resources/snapshot/89ade5ae13776cd90113876955be0356.jpeg {#blogThisImgSmall} [misc]: http://services.alphaworks.ibm.com/manyeyes/images2/blog_this_caption.jpg {#Any_13} [![][1] ![misc][]]: http://services.alphaworks.ibm.com/manyeyes/view/SNnqRHsOtha6KBUjJZqVH2- [Graphviz]: http://www.graphviz.org/ "Пакет для визуализации графов" [RSS]: http://dzhus.org/posts/2006-09-11-what-is-rss.html [OPML]: http://opml.org/ [Google Reader]: http://google.com/reader/ [make-opml.xsl]: http://github.com/dzhus/xfn-spider/blob/master/make-opml.xsl [twitter.com]: http://twitter.com/ [2]: http://www.vecosys.com/2007/05/08/twitter-now-supports-hatom-and-hcard-microformats/ [http://tantek.com]: http://tantek.com/ [Many Eyes visualization]: http://services.alphaworks.ibm.com/manyeyes/static-resources/snapshot/89ade5ae138e004a01139228cfe50154.jpeg {#blogThisImgSmall} [![Many Eyes visualization][] ![misc][misc image]]: http://services.alphaworks.ibm.com/manyeyes/view/S8_UXHsOtha6I3EtDXWYH2- [XFN crawler]: http://www.mindsack.com/?page_id=39 [grokXFN.xsl]: http://www.w3.org/2003/12/rdf-in-xhtml-xslts/grokXFN.xsl
![misc image][]