Ajax RSS Reader - парсим RSS ленту
На различных проектах часто приходится осуществлять вывод новостей со стороннего ресурса, используя его 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:
- url - путь до скрипта, к которому выполняется Ajax запрос;
- data - данные которые передаются Ajax запросом (метод GET или POST);
- secure - безопасный запрос;
- onRequest - вызывается когда ajax запрос начинает осуществлятся;
- onSuccess - вызывается если ajax запрос удачно выполнен и получен ответ;
- onFailure - вызывается если ajax запрос не удался, alert сообщит код ошибки;
Здесь можете почитать более подробней о классе 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 и сравниваем содержащуюся в нем дату с текущей
- //если текущая дата равна дате в файле news.txt
- }else{
- $url = 'http://feeds.feedburner.com/cleverscript/js';
- $file = getRSS($url);
- }
Представим что файл с записанными в него новостями с разметкой уже записан. При обращении к скрипту по 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";
- for($i=0;$i<5;$i++){
- $tpl = "<p class='news'>";
- $tpl .= "<a href='".$ml[1][$i]."'>";
- $tpl .= $mt[1][$i];
- $tpl .= "</a>";
- $tpl .= "</p>";
- }
- //close temp file
- //delete this file
- //rename temp file
- //unbloked bloked file
- //close bloked file
- if($fp){
- return $fp;
- }
- else{
- return "Ошибка при открытии файла";
- }
- }
- }
Эта функция выполняет следующее: получив во входном параметре $url - ссылку на rss ленту, выполняет запрос к ней на получение содержимого XML RSS канала, используя для этого стандартную php функцию:
$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():
Все полученные заголовки, ссылки, и даты публикации новостей из RSS, сохраняются в массивах с одинаковыми индексами, для каждой новости, то есть item. Это позволяет в цикле пройтись по этим массивам и сформировать нужную структуру HTML c данными о новости, при этом добавляя каждую новость в массив:
- for($i=0;$i<5;$i++){
- $tpl = "<p class='news'>";
- $tpl .= "<a href='".$ml[1][$i]."'>";
- $tpl .= $mt[1][$i];
- $tpl .= "</a>";
- $tpl .= "</p>";
- }
После этого определить дату, и сформировать строку с датой и html разметкой, для записи в файл "news.txt":
Обратите внимание, после даты идет перевод каретки! Это необходимо для того чтобы при считывании файла news.txt дата была первым элементом массива, что позволит сравнить ее с текущей датой.
Следующий код выполняет запись в файл сформированную строку с датой и разметкой:
- //close temp file
- //delete this file
- //rename temp file
- //unbloked bloked file
- //close bloked 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

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