Ajax RSS Reader - парсим RSS ленту

Воскресенье, 20 Февраль 2011

 

На различных проектах часто приходится осуществлять вывод новостей со стороннего ресурса, используя его RSS канал. Для этого был написан скрипт в связке ajax - php, с использованием javascript библиотеки mootools. Работает это следующим образом:

 

При загрузке страницы в браузер пользователя, осуществляется ajax запрос к скрипту php который в свою очередь осуществляет запрос по адресу RSS ленты, получая XML содержимое канала RSS. Но если предположить что сайт имеет высокую посещаемость и страницы загружаются одновременно в несколько браузеров а все эти запросы идут от нашего сервера, то владельцы источника RSS канала скорее всего поставят блокировку по IP на запросы от нашего сервера.

 

Решить эту проблему можно следующим образом - записывать в текстовый файл спарсинные новости, за текущие сутки, то-есть сверять текущую дату сервера и дату записанную в файл. И если они не совпадают, то осуществить запрос на получение RSS содержимого канала, осуществить парсинг, сформировать нужную нам структуру разметки этих новостей, и записать их в файл, а затем уже считав этот файл, отдать его содержимое в ответ на Ajax запрос, и вывести ответ на странице. А если даты соответствуют то не осуществляется запрос к RSS ленте, а просто считывается файл с имеющимися там записями новостей.

 

Теперь подробнее о том как это реализовано на Javascript и PHP. В ниже приведенном коде javascript используется экземпляр класса Request, библиотеки mootools, которую следует подключить на страницу. Этот класс выполняет ajax запрос используя метод post (в данном примере), к серверному скрипту на php, а также получает от него ответ в переменной responseText, которая будет содержать html код разметки новостей из текстового файла. Выглядит это так:

 

 
window.addEvent('domready', function(){
  new Request({
    url: 'reader/rss-reader.php',
    data: 'rss=http://feeds.feedburner.com/cleverscript/js',
    secure: true,
    onRequest: function(){
    },
    onSuccess: function(responseText){
      //console.log(responseText);
      $('news').set('html', responseText);
      $('ajax-loader').setStyle('display', 'none');
    }
  }).post();
});
 

 

Описание параметров объекта класса Request:

 

 

Здесь можете почитать более подробней о классе mootools Request: Class: Request

 

И так представим что ajax запрос успешно выполнен к серверному скрипту, которому передается ссылка на RSS канал, и от него получен ответ, в котором содержится html разметка с новостями из rss ленты, теперь этот ответ нужно разместить в нужном блоке div на web странице. Данная манипуляция осуществляется функцией при событии onSuccess:

 

 
onSuccess: function(responseText){
  $('news').set('html', responseText);
  $('ajax-loader').setStyle('display', 'none');
}
 

 

В данном случае ответ будет помещен в контейнер DIV c идентификатором "news". Также при этом событии onSuccess, скрываем картинку с идентификатором ajax-loader, которая показывается до того как будет получен ответ после ajax запроса.

 

Теперь описание серверного скрипта который выполняет вышеописанные функции по запросу к rss ленте и парсит из нее новости. Начнем от простого к сложному:

 

 
  //считываем файл news.txt и сравниваем содержащуюся в нем дату с текущей
  $file = file("news.txt");
 
  if(date('d')==str_replace("\r\n","",$file[0])){
    //если текущая дата равна дате в файле news.txt
    unset($file[0]);
    echo iconv('utf-8', 'cp1251', implode($file));
  }else{
    $url = 'http://feeds.feedburner.com/cleverscript/js';
    $file = getRSS($url);
    unset($file[0]);
    echo iconv('utf-8', 'cp1251', implode($file));
  }
 

 

Представим что файл с записанными в него новостями с разметкой уже записан. При обращении к скрипту по Ajax запросу, он выполняет считывание файла "news.txt", используя для этого функцию file(), которая считывает файл построчно и возвращает массив этих строк. В первой строке будет записана дата (о которой говорилось выше в начале статьи), это будет первый элемент массива $file[0], очистив дату от перевода каретки, сравниваем ее с текущей, и если даты равны, то удаляем первый элемент массива с датой (unset($file[0]);), объединяем массив в строку и выводим содержимое в ECHO - это будет ответ для Ajax запроса.

 

В случае если дата в файле не равна текущей дате, то в функцию getRSS($url) передается URL RSS ленты, эта функция и осуществляет запрос к RSS каналу, парсинг XML RSS, формирование html разметки новостей, и запись их в файл "news.txt". Также после вызова функции getRSS, удаляется первый элемент массива и выводится содержимое файла "news.txt", но выводится то что считалось в первый раз а не после перезаписи - вызова функции getRSS, сделано это специально для повышения производительности.

 

Еще на что нужно обратить внимание на перекодировку из UTF-8 в CP1251, в данном примере все файлы имеют кодировку CP1251, а запись в файл осуществляется в кодировке UTF-8, так как парсится лента RSS выдаваемая FeedBurner в кодировке UTF-8. И если ваши страницы сайта имеют кодировку UTF-8 вам небходимо убрать перекодирование.

 

И так функция getRSS:

 

 
  function getRSS($url){
    $path_to_file = "news.txt";
    define ("PATH_BLOCKFILE", "blocked.txt");
    define ("PATH_TEMPFILE", "temp.php");
 
    $cont = file_get_contents($url);
 
    $title = preg_match_all("#<item><title>(.*)</title>#i", $cont, $mt);
    $link = preg_match_all("#<feedburner:origLink>(.*)</feedburner:origLink>#i", $cont, $ml);
    $date = preg_match_all("#<pubDate>(.*)</pubDate>#i", $cont, $md);
 
    $arr = array();
 
    for($i=0;$i<5;$i++){
 
      $tpl = "<p class='news'>";
        $tpl .= "<a href='".$ml[1][$i]."'>";
          $tpl .= "<span class='data'>".substr($md[1][$i], 5, 11)."</span><br/>";
          $tpl .= $mt[1][$i];
        $tpl .= "</a>";
      $tpl .= "</p>";
 
      array_push($arr, $tpl);
    }
 
    $rss = date('d')."\r\n".implode($arr);
 
    $lock = fopen(PATH_BLOCKFILE,"a");
    if(flock($lock, LOCK_EX)){
      $tmp=fopen(PATH_TEMPFILE,"w");
 
      fputs($tmp, "$rss");
      //close temp file
      fclose($tmp);
      //delete this file
      unlink("$path_to_file");
      //rename temp file 
      rename(PATH_TEMPFILE, "$path_to_file");
      //unbloked bloked file
      flock($lock, LOCK_UN);
      //close bloked file
      fclose($lock);
 
      $fp = file("$path_to_file"); // Открываем файл в режиме чтения
      if($fp){
        return $fp;
      }
      else{
        return "Ошибка при открытии файла";
      }
    }
  }
 

 

Эта функция выполняет следующее: получив во входном параметре $url - ссылку на rss ленту, выполняет запрос к ней на получение содержимого XML RSS канала, используя для этого стандартную php функцию:

 

 
$cont = file_get_contents($url);
 

 

$cont - будет содержать XML RSS вот такого вида (для примера только одна новость полученная от FeedBurner):

 

 
<item>
  <title>Геолокация - определение страны по IP</title>
  <link>http://feedproxy.google.com/~r/cleverscript/js/~3/KMkqWec6AEc/40-geolocation</link>
  <guid isPermaLink="false">http://cleverscript.ru//index.php/php/scripts-php/40-geolocation</guid>
  <description>
  Определение страны по IP посетителя сайта довольно частная задача но все же она может возникнуть например для вывода определенной информации для посетителей конкретной страны, или же вывода текстов на языке страны посетителя. Ну задачи бывают разные, здесь уж кому что требуется.
  </description>
  <pubDate>Sun, 20 Feb 2011 14:01:02 +0000</pubDate>
  <feedburner:origLink>http://cleverscript.ru//index.php/php/scripts-php/40-geolocation</feedburner:origLink>
</item>
 

 

Для вашего конкретного случая советую просмотреть исходный код RSS ленты, да бы точно определится со составлением регулярных выражений, для выборки нужных данных, которые вы хотите спарсить. В данном же случае требуется получить заголовок новости, ссылку на эту новость и дату публикации. Осуществляется это с помощью функции preg_match_all():

 

 
$title = preg_match_all("#<item><title>(.*)</title>#i", $cont, $mt);
$link = preg_match_all("#<feedburner:origLink>(.*)</feedburner:origLink>#i", $cont, $ml);
$date = preg_match_all("#<pubDate>(.*)</pubDate>#i", $cont, $md);
 

 

Все полученные заголовки, ссылки, и даты публикации новостей из RSS, сохраняются в массивах с одинаковыми индексами, для каждой новости, то есть item. Это позволяет в цикле пройтись по этим массивам и сформировать нужную структуру HTML c данными о новости, при этом добавляя каждую новость в массив:

 

 
$arr = array();
for($i=0;$i<5;$i++){
 
  $tpl = "<p class='news'>";
    $tpl .= "<a href='".$ml[1][$i]."'>";
      $tpl .= "<span class='data'>".substr($md[1][$i], 5, 11)."</span><br/>";
      $tpl .= $mt[1][$i];
    $tpl .= "</a>";
  $tpl .= "</p>";
 
  array_push($arr, $tpl);
}
 

 

После этого определить дату, и сформировать строку с датой и html разметкой, для записи в файл "news.txt":

 

 
$rss = date('d')."\r\n".implode($arr);
 

 

Обратите внимание, после даты идет перевод каретки! Это необходимо для того чтобы при считывании файла news.txt дата была первым элементом массива, что позволит сравнить ее с текущей датой.

 

Следующий код выполняет запись в файл сформированную строку с датой и разметкой:

 

 
$lock = fopen(PATH_BLOCKFILE,"a");
if(flock($lock, LOCK_EX)){
  $tmp=fopen(PATH_TEMPFILE,"w");
 
  fputs($tmp, "$rss");
  //close temp file
  fclose($tmp);
  //delete this file
  unlink("$path_to_file");
  //rename temp file 
  rename(PATH_TEMPFILE, "$path_to_file");
  //unbloked bloked file
  flock($lock, LOCK_UN);
  //close bloked file
  fclose($lock);
 
  $fp = file("$path_to_file"); // Открываем файл в режиме чтения
  if($fp){
    return $fp;
  }
  else{
    return "Ошибка при открытии файла";
  }
}
 

 

Данный код записи в файл, позаимствован с этого ресурса запись информации в текстовый файл, здесь все подробно описано, поэтому не буду повторятся, хочу сказать только что код работает отлично, автору спасибо!

 

На этом все, вся логика работы данного скрипта Ajax Rss Reader, разобрана. Приведу лишь пример как подключить это к своей странице. Для этого необходимо подключить библиотеку Mootools и скрипт с ajax функцией, а также добавить в код HTML контейнер с id "news", и правильно узнать путь к серверному скрипту php. И еще выставить права на запись для папки в которой будет находится данный скрипт, так как в ней будут создаваться файлы, в том числе и news.txt.

 

Пример подключения Ajax Rss Reader`a:

 

 
<head>
<script type="text/javascript" src="js/mootools-1.2.4-core-yc.js"></script>
<script type="text/javascript" src="js/get-rss.js"></script>
</head>
<body>
  <div class="wrapper">
    <h3>Ajax RSS Reader - парсим RSS ленту <img id="ajax-loader" alt="" src="img/ajax-loader.gif"/></h3>
    <div id="news"></div>
  </div>
</body>
</html>
 

 

P/S Настоятельно рекомендую просматривать XML код RSS ленты которую вы хотите спарсить, в случае если ее формат RSS будет не RSS 2.0 или некорректным, регулярка может не работать! Поэтому экспериментируйте!

 

Посмотреть пример: Ajax RSS Reader.

Скачать пример: Ajax RSS Reader.

 

PS. Читайте последние записи RSS Подписка на RSS

 

Метки:

Похожие статьи:

Комментарии 

 
anonim Среда, 20 Апрель 2011

Я практически случайно зашел на этот сайт, но задержался тут надолго. Задержался, потому что все очень интересно. Обязательно скажу о вас всем своим друзьям.

 

 
 
anonim Вторник, 26 Апрель 2011

У меня не работает скрипт. Не могу понять в чем проблема. При отправке данных на сервер, нет ответа. Хотя скрипт-обработчик отдельно работает. Я так понимаю, что сбой происходит где-то на уровне mootools.
Поставила алерт в onSuccess, который отображает "responseText". Алерт срабатывает, но он пустой. Подскажите, пожалуйста, как можно это исправить.

P.S. На Вашем сайте баг с размещение комментариев.

 

 
 
anonim Суббота, 30 Апрель 2011

Замечательно, это очень ценная штука

 

 
 
anonim Воскресенье, 01 Май 2011

Милана>>>
1. во первых проверьте в FireBug нет ли ошибки в Javascript;
2. во вторых в конфигурации вашего сервера\хостинг а должна быть включена опция "fopen wrappers";
3. в третьих возможно проблема в кодировке, попробуйте закоментировать 13 строку в файле rss-reader.php вот так: //$cont = iconv('utf-8', 'cp1251', $cont);
4. и на файлы news.txt и blocked.txt установите права на запись.


P.S. бага нет, просто комментарии подлежат модерации

 

 
 
anonim Вторник, 03 Май 2011

Найс пост! Сенкью!

 

 
 
anonim Воскресенье, 08 Май 2011

Хорошо сказано.

 

 
 
anonim Четверг, 29 Март 2012

Спасибо за статью очень достойный сайт.

 

 

Добавить комментарий