Все о парсинге RSS лент средствами PHP
Среда, 30 сентября 2009 г.
Просмотров: 7984
Подписаться на комментарии по RSS
RSS — семейство XML-форматов, предназначенных для
описания лент новостей, анонсов статей, изменений в блогах и т. п.
Информация из различных источников, представленная в формате RSS, может
быть собрана, обработана и представлена
пользователю в удобном для него
виде специальными программами-агрегаторами.
То есть это по сути XML (кто незнает что это идем в википедию и читаем),
а XML как нам известно хорошо структурированный документ. Я клоню к
тому что если в RSS есть открывающий тег, то должен быть и закрывающий
(например: <title>Заголовок</title>), иначе это не RSS.
Думаю на данном этапе суть ясна: нам нужно получить информацию
заключенную между тегами. Любая RSS лента имеет заголовок заключенный
между тегами <title></title> и сам текст статьи заключенный
между тегами < description></description>, именно их нам и
нужно спарсить.
Теперь расскажу о способах написания RSS парсера и что предлагает нам PHP для реализации.
Способ 1 – SimpleXML
SimpleXML – это расширение для PHP5 устанавливаемое
в него по умолчанию, представляет самый простой и элегантный способ
обработки XML (соответственно и RSS) файлов. Это и наиболее
предпочтительный способ, но он стал доступным только в 5 версии PHP.
Тут нет ничего проще, данный код наглядно показывает как просто парсить
RSS ленты средствами SimpleXML:
<code><span class="pun"><?</span><span class="pln"> $url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'rss.xml'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//адрес RSS ленты</span><span class="pln"> $rss </span><span class="pun">=</span><span class="pln"> simplexml_load_file</span><span class="pun">(</span><span class="pln">$url</span><span class="pun">);</span><span class="pln"> </span><span class="com">//Интерпретирует XML-файл в объект</span><span class="pln"> </span><span class="com">//цикл для обхода всей RSS ленты</span><span class="pln"> </span><span class="kwd">foreach</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$rss</span><span class="pun">-></span><span class="pln">channel</span><span class="pun">-></span><span class="pln">item </span><span class="kwd">as</span><span class="pln"> $item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> echo </span><span class="str">'<h1>'</span><span class="pun">.</span><span class="pln">$item</span><span class="pun">-></span><span class="pln">title.</span><span class="str">'</h1>'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//выводим на печать заголовок статьи </span><span class="pln"> echo $item</span><span class="pun">-></span><span class="pln">description</span><span class="pun">;</span><span class="pln"> </span><span class="com">//выводим на печать текст статьи</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">?></span></code>
Данный код выведет заголовки и тексты статей из RSS ленты. Просто
ведь? Этим SimpleXML и привлекает. Дальше вам нужно будет только
правильно распорядиться полученными данными, записать в базу или еще
куда-нибудь.
Способ 2 – XML Parser Functions
XML Parser Functions - это стандартные функции PHP
для работы с XML доступные начиная c 4-ой версии PHP. Тоже нет ничего
сложного, правда в отличие от SimpleXML совсем не элегантно.
Продемонстрирую пример:
<code><span class="pun"><?</span><span class="pln"> $url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'rss.xml'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//адрес RSS ленты</span><span class="pln"> $xml </span><span class="pun">=</span><span class="pln"> xml_parser_create</span><span class="pun">();</span><span class="pln"> </span><span class="com">//создаёт XML-разборщик</span><span class="pln"> xml_parser_set_option</span><span class="pun">(</span><span class="pln">$xml</span><span class="pun">,</span><span class="pln"> XML_OPTION_SKIP_WHITE</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="com">//устанавливает опции XML-разборщика</span><span class="pln"> xml_parse_into_struct</span><span class="pun">(</span><span class="pln">$xml</span><span class="pun">,</span><span class="pln"> file_get_contents</span><span class="pun">(</span><span class="pln">$url</span><span class="pun">),</span><span class="pln"> $element</span><span class="pun">,</span><span class="pln"> $index</span><span class="pun">);</span><span class="pln"> </span><span class="com">//разбирает XML-данные в структуру массива</span><span class="pln"> xml_parser_free</span><span class="pun">(</span><span class="pln">$xml</span><span class="pun">);</span><span class="pln"> </span><span class="com">//освобождает XML-разборщик</span><span class="pln"> $count </span><span class="pun">=</span><span class="pln"> count</span><span class="pun">(</span><span class="pln">$index</span><span class="pun">[</span><span class="str">"TITLE"</span><span class="pun">])-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">//число проходов цикла.</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> $i </span><span class="pun"><</span><span class="pln"> $count</span><span class="pun">;</span><span class="pln"> $i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> echo </span><span class="str">'<h1>'</span><span class="pun">.</span><span class="pln">$element</span><span class="pun">[</span><span class="pln">$index</span><span class="pun">[</span><span class="str">"TITLE"</span><span class="pun">][</span><span class="pln">$i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]][</span><span class="str">"value"</span><span class="pun">]</span><span class="pln">.</span><span class="str">'</h1>'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//выводим на печать заголовок статьи </span><span class="pln"> echo $element</span><span class="pun">[</span><span class="pln">$index</span><span class="pun">[</span><span class="str">"DESCRIPTION"</span><span class="pun">][</span><span class="pln">$i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]][</span><span class="str">"value"</span><span class="pun">];</span><span class="pln"> </span><span class="com">//выводим на печать текст статьи</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">?></span></code>
Вот таким образом мы получаем интересующие нас содержимое элементов
RSS. Но тут уже нужно разобраться с массивами которые создает XML
разборщик.
Способ 3 – Написать RSS парсер самому
Например я делал именно так, когда не знал про существование
SimpleXML и XML Parser Functions. Приведу небольшой пример парсинга RSS
обычным процедурным PHP кодом, тут за парсинг отвечает функция
preg_match_all(), которая выполняет глобальный поиск шаблона в строке.
Данный пример не совершенен и парсит только титлы и дескрипшены у RSS:
<code><span class="pun"><?</span><span class="pln"> $url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'rss.xml'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//адрес RSS ленты</span><span class="pln"> $rss </span><span class="pun">=</span><span class="pln"> @file_get_contents</span><span class="pun">(</span><span class="pln">$url</span><span class="pun">);</span><span class="pln"> </span><span class="com">//получаем содержимое RSS лент в виде одной строки</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$rss</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> preg_match_all</span><span class="pun">(</span><span class="str">"/title>[^>]+>/"</span><span class="pun">,</span><span class="pln"> $rss</span><span class="pun">,</span><span class="pln"> $title</span><span class="pun">);</span><span class="pln"> </span><span class="com">//парсим титлы</span><span class="pln"> preg_match_all</span><span class="pun">(</span><span class="str">"/<description>[^<]+<\/description>/"</span><span class="pun">,</span><span class="pln"> $rss</span><span class="pun">,</span><span class="pln"> $description</span><span class="pun">);</span><span class="pln"> </span><span class="com">//парсим дескрипшены</span><span class="pln"> $count </span><span class="pun">=</span><span class="pln"> count</span><span class="pun">(</span><span class="pln">$title</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">//число проходов цикла.</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> $i </span><span class="pun"><</span><span class="pln"> $count</span><span class="pun">;</span><span class="pln"> $i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> echo </span><span class="str">'<h1>'</span><span class="pun">.</span><span class="pln">substr</span><span class="pun">(</span><span class="pln">$title</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="pln">$i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">],</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">8</span><span class="pun">)</span><span class="pln">.</span><span class="str">'</h1>'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//выводим на печать заголовок статьи </span><span class="pln"> echo substr</span><span class="pun">(</span><span class="pln">$description</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="pln">$i</span><span class="pun">],</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">14</span><span class="pun">);</span><span class="pln"> </span><span class="com">//выводим на печать текст статьи</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> echo </span><span class="str">'<font color="red">Ошибка парсинга '</span><span class="pun">.</span><span class="pln">$url.</span><span class="str">'</font>'</span><span class="pun">;</span><span class="pln"> </span><span class="com">//выводим ошибку если file_get_contents() вернула false</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">?></span></code>
Таким же способом можно и отпарсить остальные элементы RSS ленты, главное написать правильно регулярку.
На этих трех способах мы и остановимся, еще есть наверняка множество
сторонних скриптов и классов в PHP для парсинга XML, например magpieRSS
у которого проблемы с кодировкой при парсинге и решить ее у меня не
получилось, да собственно не очень то и хотелось, когда есть SimpleXML
и XML Parser Functions. Вот кстати о проблемах с кодировкой мы сейчас и
поговорим…
Проблемы с кодировкой
RSS ленты как правило находятся в кодировке UTF-8, при парсинге
русского текста тремя способами описанными выше, нам на экран выводятся
кракозябры. Все потому, что тест к нам приходит в кодировке UTF-8. Для
того что бы вывести нормальные РУССКИЕ буквы нужно перекодировать
спарсеный текст из кодировки UTF-8 в Windows-1251. Для этих целей в PHP
существует функция iconv(),
но она доступна не на всех серверах и чтобы избежать дальнейших проблем
с вашим RSS парсером советую использовать самописную функцию
перекодировки. Вникать в тонкости кодировок и разбираться как из одной
кодировки получается другая думаю вам не хочется, так же не хотелось и
мне. Немного погуглив я нашел замечательную функцию перекодировки из UTF-8 в Windows-1251 и обратно,
предоставляет ее некий товарищ E64F. Возможно конечно он тоже ее где-то
слямзил, но это не так важно, важно то что она мне очень понравилась по
сравнению с другими нагуглеными функциями. Выкладываю функцию и пример
ее использования:
<code><span class="pun"><?</span><span class="pln"> echo utf8_convert</span><span class="pun">(</span><span class="pln">$str</span><span class="pun">,</span><span class="pln"> </span><span class="str">"w"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//перекодирует $str из UTF-8 в Windows-1251 и выведет на экран</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> utf8_convert</span><span class="pun">(</span><span class="pln">$str</span><span class="pun">,</span><span class="pln"> $type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> $conv </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">is_array</span><span class="pun">(</span><span class="pln">$conv</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> $conv </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">();</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$x</span><span class="pun">=</span><span class="lit">128</span><span class="pun">;</span><span class="pln"> $x </span><span class="pun"><=</span><span class="pln"> </span><span class="lit">143</span><span class="pun">;</span><span class="pln"> $x</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'utf'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">209</span><span class="pun">)</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> chr</span><span class="pun">(</span><span class="pln">$x</span><span class="pun">);</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'win'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="pln">$x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">112</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$x</span><span class="pun">=</span><span class="lit">144</span><span class="pun">;</span><span class="pln"> $x</span><span class="pun"><=</span><span class="pln"> </span><span class="lit">191</span><span class="pun">;</span><span class="pln"> $x</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'utf'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">208</span><span class="pun">)</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> chr</span><span class="pun">(</span><span class="pln">$x</span><span class="pun">);</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'win'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="pln">$x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">48</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'utf'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">208</span><span class="pun">)</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">129</span><span class="pun">);</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'win'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">168</span><span class="pun">);</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'utf'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">209</span><span class="pun">)</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">145</span><span class="pun">);</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'win'</span><span class="pun">][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> chr</span><span class="pun">(</span><span class="lit">184</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$type </span><span class="pun">==</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> str_replace</span><span class="pun">(</span><span class="pln">$conv</span><span class="pun">[</span><span class="str">'utf'</span><span class="pun">],</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'win'</span><span class="pun">],</span><span class="pln"> $str</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> elseif </span><span class="pun">(</span><span class="pln">$type </span><span class="pun">==</span><span class="pln"> </span><span class="str">'u'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> str_replace</span><span class="pun">(</span><span class="pln">$conv</span><span class="pun">[</span><span class="str">'win'</span><span class="pun">],</span><span class="pln"> $conv</span><span class="pun">[</span><span class="str">'utf'</span><span class="pun">],</span><span class="pln"> $str</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> $str</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">?></span></code>
Функция utf8_convert() принимает 2 параметра: $str – наша строка
которую нужно перекодировать и $type – в какую кодировку нужно
кодировать (“w” – из utf в win, “u” – из win в utf). Как это применить
к нашим 3-м способам парсинга RSS думаю разберетесь, если хоть немного
знаете PHP.
источник
Оставьте комментарий!