Парсинг feed Яндекс Фотки с помощью xpath и SimpleXML

Яндекс Фотки - крайне популярный ресурс! Как для хранения личных фотографий, так и для хранения любых графических файлов вообще - своего рода CDN для массового размещения картинок.Все фотографии разложены по альбомам, а каждый альбом имеет свой фид, то есть xml-файл в котором хранится вся информация о каждой фотографии, как-то:

  • автор
  • дата загрузки
  • уровень доступа
  • название описание
  • и т.д.

По сути, xml-фид это база данных хранящая в себе всю информацию относительно альбома и каждой фотографии. В общем, https://fotki.yandex.ru это очень удобно и с этим удобством необходимо уметь работать.

Стандартный фид альбома Яндекс Фоток имеет такой вид

<feed xmlns="http://www.w3.org/2005/Atom" 
    xmlns:app="http://www.w3.org/2007/app" 
    xmlns:f="yandex:fotki">
  <id>urn:yandex:fotki:styleroom:album:156904:photos</id>
  <author>
    <name>styleroom</name>
    <f:uid>13223519</f:uid>
  </author>
  <title>Лядины</title>
  <updated>2016-05-28T18:48:03Z</updated>
  <summary>Каргополье, Архангельская область</summary>
  <link href="http://path_to/album/156904/photos/" rel="self" />
  <link href="http://path_to/album/156904/" rel="alternate" />
  <entry>
    <id>urn:yandex:fotki:styleroom:photo:700417</id>
    <author>
      <name>styleroom</name>
      <f:uid>13223519</f:uid>
    </author>
    <title>2.jpg</title>
    <summary>Помошница</summary>
    <link href="http://path_to/photo/700417/" rel="self" />
    <link href="http://path_to/photo/700417/" rel="edit" />
    <link href="http://path_to/view/700417/" rel="alternate" />
    <link href="http://path_to_orig" rel="edit-media" />
    <link href="http://path_to/album/156904/" rel="album" />
    <published>2016-05-27T05:45:11Z</published>
    <app:edited>2016-05-28T18:49:35Z</app:edited>
    <updated>2016-05-28T18:49:35Z</updated>
    <f:access value="public" />
    <f:xxx value="false" />
    <f:hide_original value="false" />
    <f:disable_comments value="false" />
    <f:img height="75" href="http://path_to_XXS" size="XXS" width="75" />
    <f:img height="800" href="http://path_to_XL" size="XL" width="538" />
    <f:img height="300" href="http://path_to_M" size="M" width="202" />
    <f:img height="500" href="http://path_to_L" size="L" width="336" />
    <f:img height="50" href="http://path_to_XXXS" size="XXXS" width="50" />
    <f:img height="150" href="http://path_to_S" size="S" width="101" />
    <f:img height="100" href="http://path_to_XS" size="XS" width="67" />
    <f:img bytesize="149433" height="960" href="http://path_to_orig" size="orig" width="646" />
    <f:img height="960" href="http://path_to_XXL" size="XXL" width="646" />
    <category scheme="http://path_to/tags/" term="бабушка" />
    <category scheme="http://path_to/tags/" term="внучка" />
    <category scheme="http://path_to/tags/" term="грабли" />
    <content src="http://path_to_orig" type="image/*" />
  </entry>
  ...
  <f:image-count value="27" />
</feed>

Наша задача - получить необходимую информацию об одной фотографии или нескольких используя php-расширение SimpleXML и языка запросов к элементам XML-документа xpath.

Стратегия работы с фидом альбома Яндекс Фоток может идти тремя путями:

  1. перебор всего альбома
  2. использование нескольких фотографий
  3. работа с одной фотографией

Разница в этих стратегиях будет в осуществлении первичной выборки.

Тактика же будет одинаковой для всех: перебор узлов внутри выборки с использованием xpath.

Глядя на фид, давайте поймем - какую информацию из него мы будем извлекать, чтобы систематизировать наглядность рабочего кода. В тренировочных целях, предлагаю извлечь из фида следующие элементы:

об альбоме в целом

  1. ID альбома
  2. название альбома
  3. описание альбома
  4. автора альбома

об отдельной фотографии

  1. название
  2. автор
  3. описание
  4. теги-метки
  5. путь к оригиналу
  6. размер оригинала в байтах
  7. уровень доступа
  8. дата публикации

Начнем мы с загрузки файла фида и создания нэймспейсов (пространства имен)

$xml = simplexml_load_file('http://api-fotki.yandex.ru/api/users/styleroom/album/156904/photos/');
$xml->registerXPathNamespace('c', 'http://www.w3.org/2005/Atom');
$xml->registerXPathNamespace('f', 'yandex:fotki');

Работаем с альбомом

Тут все совсем просто

// ID альбома
echo substr($xml->id, strpos($xml->id, 'album:')+6, -7);
// название альбома
echo $xml->title;
// описание альбома
echo $xml->summary;
// автор альбома
echo $xml->author->name;

Работаем с фотографиями

Здесь, для начала, придется определиться с с количеством выбираемых фотографий

1. Выбираем все из альбома. Здесь нам не надо делать дополнительных телодвижений.

$arr = $xml->entry;
foreach ($arr as $val) {...}

2. Выбираем несколько из всего альбома по условию. Это означает, что необходимо осуществить запрос по некоему условию. Допустим, выберем те фотографии, у которых есть тег-метка "бабушка". Это будет так.

$arr = $xml->xpath("//*[*/@term=\"бабушка\"]");
foreach ($arr as $val) {...}

3. Выбираем только одну фотографию. Тут придется указать точное название, дабы получить точно только один узел entry/

$arr = $xml->xpath("//*[c:title=\"Название фото\"]");
foreach ($arr as $val) {...}

Теперь все в порядке: в переменной $val будет находится несколько или один узел entry внутри которого и будет располагаться интересующая нас информация: узлы link, f:img, category, content и др.

Чтобы получить к ним доступ, во время перебора в цикле foreach, мы будем использовать xpath такого вида

$var = $val->xpath('*[здесь-условие]');
$var = $val->xpath('узел[здесь-условие]');

Переходим к решению наших задач по каждой отдельной фотографии

// номер / ID
echo substr($val->id, strrpos($val->id, ':')+1);
// название
echo $val->title;
// автор
echo $val->author->name;
// описание
echo $val->summary;
// теги-метки 
foreach ($val->category as $v) { 
    echo (string)$v->attributes()->term.',';
}
// путь к картинке-оригиналу 
(string)$val->content->attributes()->src;
// страница просмотра
$link = $val->xpath('*[@rel="alternate"]');
echo (string)$link[0]->attributes()->href;
// размер оригинала в байтах 
$size = $val->xpath('*[@bytesize]');
echo (string)$size[0]->attributes()->bytesize;
// уровень доступа 
$facc= $val->xpath('f:access');
echo (string)$facc[0]->attributes()->value;
// дата публикации 
echo $val->published
// картинка по индексу M 
$fimg = $val->xpath('*[@size="M"]');
echo (string)$fimg[0]->attributes()->href;

Вот, пожалуй, и все.