Как написать парсер HTML на PHP
Много разных задач сводятся к парсинку HTML. И не только сбор контента для ГС. Вот мне например понадобилось разобрать HTML собственного контента, чтобы культурненько облагородить. Ну например внешние ссылочки спрятать.
Сначала я подумал – фигня. Найти в тексте строчку “<a href=http://” и получи себе внешнюю ссылочку. Но ведь в контенте теги и атрибуты могут писаться с заглавной буквы. И ещё между A и HREF может стоять произвольное количество пробелов. Но самое главное, между A и HREF могут быть разные всякие другие слова. Короче выхода нет, кроме как строить нормальное дерево DOM и его анализировать. То бишь парсить.
Но оказывается библиотека парсера давно есть и встроена в PHP. Осталось только попользоваться!
Расписывать не буду. Мануал превзойти тяжело. А примерчик для направления – самый раз будет.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// Содаём объект $dom = new domDocument; $dom->strictErrorChecking=false; $dom->recover = true; // скармливаем объекту готовую строку $dom->loadHTML($strHTML); //или удобнее будет файл? $dom->loadHTMLFile($htmlFile); //И всё! Можно вытащить любой аттрибут любого элемента! foreach($dom->getElementsByTagName('img') as $img_dom) $img_src= html_entity_decode($img_dom->getAttribute('src')); // А вот можно переделать ссылку на свой хитрый редирект $link_dom->setAttribute('href','/link/redirect/'.$link->id); } В результате можно вывести код, который получился в результате. echo $dom->saveHTML(); |
Пара слов про кириллицу
=======================
Раз уж вы читаете этот сайт на русском языке, то и парсить вероятно будете тоже русскоязычный сайт. А вот с ними не всё так просто.
В документации написано, что класс делает utf_encode, но ситуация ещё сложнее. Вот пример
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php $dom = new domDocument('1.0', 'UTF-8'); $dom->loadHTML("<p>Германия, Великобритания и Франция</p>"); // Тут работает foreach($dom->getElementsByTagName('p') as $p_dom) echo utf8_decode ($p_dom->nodeValue); // А тут фигня echo utf8_decode($dom->saveHTML()); // Тут по-лучше, но всё равно фигня echo html_entity_decode($dom->saveHTML()); ?> |
По этому примеру понятно, что преобразование похоже на htmlentities, но не совсем оно.
В общем чтобы не мучиться я решил зашифровать кириллицу в url_encode. Потом делаешь url_decode – и кириллица работает. Но есть проблема – знаки тегов тоже конвертируются, и это мешает парсить HTML. Я решил проблему путём написания простенькой функции. Теперь код выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php function my_urlencode($str) { // То же urlencode, но только кириллицы $tr = array( '%3C' =>'<', '%3E' =>'>', '%3D' =>'=', '+' =>' ', '%22' =>'"', '%27' =>'\'', '%21' =>'!','%2F' =>'/','%3A' =>':' ); $str=strtr(urlencode($str),$tr); return $str; } $dom = new domDocument('1.0', 'UTF-8'); $dom->loadHTML(my_urlencode("<p>Германия, Великобритания и Франция</p>")); // Тут работает foreach($dom->getElementsByTagName('p') as $p_dom) echo urldecode($p_dom->nodeValue); // И так работает echo urldecode($dom->saveHTML()); ?> |
Теперь точно работает.
Как написать парсер HTML на PHP - Генератор расширений Joomla и многое другое на нашем сайте посвященном работе расширений, компонентов, модулей, плагинов для линейки Joomla. Отправляйте ссылку на страницу своим друзьям и в социальные сети воспользовавшись графическими иконками выше.