Недавно мы писали о нашем валидаторе семантической разметки. А сегодня хотим рассказать, зачем и почему он был сделан, какие сложности возникли при разработке и как мы с ними справились. Одна из причин, по которой мы его сделали, конечно, в том, что мы хотели избавить роботов от встреч с ошибками вебмастеров. Но руководствовались мы не только этим.
Медленно, но верно семантическая разметка набирает популярность. Чуть больше десяти лет назад (в мае 2001 года) впервые был введен термин «семантическая паутина». В 2004 году появилось первое упоминание формата RDFa, примерно тогда же начали развиваться микроформаты. В июне 2011 года был запущен стандарт schema.org.
Сейчас семантическую микроразметку поддерживают и Яндекс, и другие ведущие мировые поисковые системы.
Однако вебмастера часто сталкиваются с тем, что валидаторы HTML выдают массу ошибок. Дело в том, что большинство из них не поддерживают микроразметку. Например, validator.w3.org поддерживает HTML5 в тестовом режиме и воспринимает микроданные как ошибку:
Существует много инструментов для проверки семантической разметки. Некоторые из них универсальны (например, http://validator.nu/), другие – проверяют конкретный тип разметки. Есть валидаторы RDFa (checkrdfa, w3.org/RDF/Validator/, rdfabout.com и другие), валидатор OpenGraph у Facebook, валидаторы микроформатов (например, валидатор hCard). Поисковые системы, использующие разметку, предлагают свои валидаторы.
Когда Яндекс стал использовать микроформаты и schema.org в своих сервисах, выяснилось, что у каждого потребителя разметки есть свои особенности её использования и свой набор расширений. Поэтому валидатор делает жизнь вебмастера намного проще. К тому же мы предупреждаем не только об ошибках в стандарте, но и о том, что нужно изменить в разметке, чтобы мы смогли использовать данные в своих сервисах.
Разработка универсального валидатора семантической разметки
Сейчас валидатор обрабатывает все популярные виды семантической микроразметки (микроформаты, микроданные, RDFa) и популярные словари (schema.org, OpenGraph). Эти форматы отличаются между собой логикой встраивания на страницу и внутренней структурой.
Сложнее всего разбирать микроформаты. Видимо, при их разработке больше внимания уделяли удобству встраивания на страницу, а не простоте извлечения данных.
Микроформаты встраиваются как классы CSS, и, чтобы найти их на странице, надо понимать их структуру. При этом они могут быть вложены друг в друга. Или один микроформат может быть полем другого. Некоторые микроформаты в одних случаях могут быть самостоятельными, а в других – полями других форматов. Например, hCard может использоваться и сам по себе, и в качестве поля. Другие сами по себе никогда не встречаются (например, поле adr в hCard).
В нашем валидаторе микроразметки есть небольшой фреймворк, который понимает логику разбора разных форматов микроразметки. Благодаря ему мы можем отдельно добавлять новые поля или даже целые типы разметки.
Рассмотрим на примере фрагмента кода, который парсит и валидирует микроформат hRecipe:
public class HRecipe extends Microformat {
final private static HRecipe instance = new HRecipe("hrecipe", true);
protected HRecipe(@NotNull final String name, final boolean root) {
super(name, root);
}
/**
* Указываем список полей данного микроформата.
* Есть несколько видов свойств:
* MFPropertySingular – не более одного значения у поля,
* MFPropertyPlural – множественные значения, MFPropertyConcatenated – множественные
* значения, объединяемые в одно.
* Для каждого поля задается его имя и типы данных, которые могут в нем встретиться.
*/
static {
instance.addProperty(new MFPropertySingular("fn", TextProperty.getInstance()));
instance.addProperty(
new MFPropertyPlural("ingredient", Ingredient.getInstance(), TextProperty.getInstance()));
instance.addProperty(new MFPropertySingular("yield", TextProperty.getInstance()));
instance.addProperty(
new MFPropertySingular("instructions", Instructions.getInstance(), TextProperty.getInstance()));
...
instance.addProperty(new MFPropertySingular("result-photo", URIProperty.getInstance()));
instance.addProperty(new MFPropertySingular("summary", TextProperty.getInstance()));
}
...
}
При разборе микроформатов в дереве выделяются точки, которые могут быть корневыми. Затем находятся все элементы, которые могут быть использованы в качестве полей (adr, fn и т.д.). После этого формат очищается от вложенных карточек. Затем начинается разбор формата. Если обнаруживаются поля, которые тоже являются микроформатами, они разбираются рекурсивно. Увидеть, как это работает, можно на примере микроформата hCard:
<div class="vcard">
<!-- поля fn org url относятся к корневому микроформатному объекту -->
<a class="fn org url" href=" http://www.commerce.net/"> CommerceNet </a>
<!-- поле adr является комплексным (то есть само по себе является микроформатным объектом) и содержит в себе другие поля: street-address, locality и пр. -->
<div class="adr">
<span class="type">Work</span>:
<div class="street-address">169 University Avenue</div>
<span class="locality">Palo Alto</span>, <abbr class="region" title="California">CA</abbr>
<span class="postal-code">94301</span>
<div class="country-name">USA</div>
</div>
<!-- поле tel так же комплексно и содержит поле type -->
<div class="tel">
<span class="type">Work</span> +1-650-289-4040
</div>
<div class="tel">
<span class="type">Fax</span> +1-650-289-4041
</div>
<div>Email:
<span class="email">info@commerce.net</span>
</div>
<!-- так же комплексные поля могут содержать тот же микроформат, что и основной объект. Например поле agent содержит объект микроформата hCard-->
<div class="agent vcard">Contact person:
<a class="fn n email" href=" mailto:johndow@commerce.net">John Dow</a>
</div>
<!-- а этот объект hCard просто вложен внутрь корневого, но никак не влияет на его разбор -->
<div class="vcard">See also:
<a class="fn org url" href=" http://www.yellowpages.com/ATT">AT&T</a>
</div>
</div>
Все микроформаты различаются по своей внутренней структуре и по составу полей. Интересен, например, формат hResume (вернее, драфт этого формата – у него, как и у многих других, пока нет завершенной версии). В этом формате поле experience (опыт работы) одновременно задается как hCalendar (для указания временного промежутка) и hCard (для описания организации, в которой человек работал). Таким образом, есть поля, которые относятся к двум карточкам одновременно. При разборе других микроформатов мы каждое поле относили к одной карточке. Это помогало нам разделять произвольно вложенные друг в друга микроформаты. Чтобы научиться разбирать резюме, не ломая логику работы парсера, мы добавили в фреймворк свой искусственный тип данных – расширенный hCalendar, в который складываем все поля, относящиеся к опыту работы. Таким образом, мы разбираем этот микроформат не совсем по спецификации, зато правильно.
<div class="hresume">
<div class=" position first experience vevent vcard summary-current" style="display:block">
<span class="n fn" id="name">
<span class="full-name"><span class="given-name">Peter</span> <span class="family-name">Savelyev</span></span>
</span>
<div class="postitle">
<h4><strong>
<a class="company-profile" href="/company/10718?trk=pro_other_cmpy"><span class="org summary">Yandex</span></a>
</strong>
</h4>
</div>
<p class="period">
<abbr class="dtstart" title="2011-07-01">июль 2011 г.</abbr>
<abbr class="dtstamp" title="2012-12-11">настоящее время</abbr>
<span class="duration"><span class="value-title" title="P1Y6M"> </span>(1 год 6 месяцев)</span>
</p>
<p class="description current-position">structured information extraction using semantic technologies</p>
</div>
</div>
Парсер обработает этот пример так:
hresume
experience
vevent
vcard
fn = Peter Savelyev
n
family-name = Savelyev
given-name = Peter
org = Yandex
dtstamp = 2012-12-11
dtstart = 2011-07-01
duration = P1Y6M
summary = Yandex
description = structured information extraction using semantic technologies
Многие микроформаты не имеют готовых спецификаций, хотя уже активно используются. Сейчас окончательно определены только hCalendar, hCard и несколько rel. Остальные – это черновые версии спецификаций разной степени готовности: некоторые почти готовы (например, hRecipe), другие далеки от совершенства и имеют ряд неопределенностей (например, hListing). Многие из микроформатов определяются только примерами, поэтому в спорных ситуациях бывает сложно принять обоснованное решение.
hListing – это микроформат для описания товаров и услуг. Для него пока не существует формального описания поля listing action, характеризующего вид услуги (продажа, покупка), поэтому вебмастера здесь поступают на свое усмотрение. Например, так:
<div class="hlisting">
...
<span class="offer rent">Аренда</span>
...
</div>
или так
<div class='hlisting offer-rent'>
...
</div>
Поддержку этого формата мы отложили до выхода более полной версии спецификации.
Со словарем schema.org тоже не всегда удобно работать. В реальном мире микроразметка работает иначе, чем она могла бы работать в идеальных условиях.
Например, для ссылок можно разметить только url. Однако в самом тексте ссылки может содержаться полезная информация. Поэтому наш парсер сейчас сохраняет не только ссылку – как нужно было бы делать по спецификации – но и текст:
<a onclick="(new Image()).src='/rg/title-overview/director-1/images/b.gif?link=%2Fname%2Fnm0000487%2F';" href="/name/nm0000487/" itemprop="director">Ang Lee</a></div>
Если разбирать этот пример по правилам, то в поле «режиссер» будет расположена только ссылка "/name/nm0000487/", однако в большинстве случаев такой информации недостаточно. Поэтому наш парсер извлечет данные следующим образом:
director
href = /name/nm0000487/
text = Ang Lee
Самая частая проблема при валидации и использовании любой микроразметки — ошибки вебмастеров. Страницы не всегда содержат верную разметку, иногда она неправильно встроена на страницу и т. д. Валидатор всегда предупреждает об ошибке (или просто о том, что данных недостаточно для использования в сервисах Яндекса). Мы стараемся сделать предупреждения об ошибках максимально понятными и конкретными.
При этом мы стремимся максимально использовать данные, даже если они содержат ошибки. Поэтому иногда мы предупреждаем об ошибке, но наш парсер успешно извлекает даже некорректно размеченные данные.
А вот с форматом RDFa проблем не возникло. Хотя и здесь есть нюанс. Дело в том, что RDFa позволяет сущностям ссылаться друг на друга, то есть дает возможность для создания циклов. Однако если в значении одной сущности есть ссылка на другую, мы воспринимаем ее как ссылку, а не подставляем описание сущности. Такое решение не противоречит официальной спецификации и предотвращает возможные проблемы.
Благодаря разным словарям с помощью RDFa можно разметить самые разные данные. Некоторые из словарей наш валидатор уже умеет понимать, другие только в планах. Сейчас один из самых популярных словарей – OpenGraph. Для него в результатах проверки у нас даже есть отдельный префикс –«og».
Результаты
Сейчас наш валидатор поддерживает все популярные типы микроразметки. Даже те, которые пока не используются в сервисах Яндекса. Нам хочется облегчить жизнь вебмастерам, которые интересуются семантическим вебом, и помочь им разобраться с ошибками. Для этого мы, в частности, написали раздел помощи по валидатору, введение в schema.org и справку по использованию микроформатов.
Немного статистики
Больше половины запросов к валидатору содержат разметку Schema.org. При этом примерно в 9% валидатор находит ошибки.
Запросы, содержащие микроформат hCard, составляют примерно 20%, и ошибки обнаруживаются примерно в 10% случаев.
Около 4% запросов – это RDFa, и около 10% примеров содержат ошибки.
OpenGraph составляет всего около 1,5% запросов, но и ошибок в этом формате практически нет. Всего в 1% случаев валидатор сообщает о некорректной разметке. Однако не удивляйтесь, если при проверке кода, содержащего OpenGraph, увидите предупреждения. Дело в том, что Яндекс пока принимает только og:video, о чем и сообщает валидатор, – при этом проверять он может и другие виды этой разметки.
А порядка 2% запросов – это проверка примеров, расположенных на главной странице валидатора.
Мы не собираемся останавливаться на достигнутом и планируем сделать интерфейс валидатора еще более наглядным и простым. Например, визуально отделить ошибки и предупреждения, относящиеся к стандарту, от ошибок и предупреждений сервисов Яндекса. И, разумеется, как можно активнее использовать в наших сервисах данные, полученные с помощью микроразметки. В ближайшем будущем мы продолжим рассказывать вам полезную информацию о микроразметке, о том, как удобнее ее встраивать и где лучше использовать. А если вы хотите узнать что-то конкретное – пишите об этом в комментариях, и мы постараемся ответить на ваши вопросы в следующих постах.
Автор: Rasifiel