Я думаю, вы уже прочувствовали неудобство регулярок на себе. Все-таки, они не очень удобны для разбора HTML кода. Поэтому существуют специальные библиотеки, позволяющие упростить разбор HTML. Их представителем является phpQuery, которую мы сейчас и разберем (остальные библиотеки изучим попозже).
Почему мы начинаем с phpQuery? Потому что она имитирует библиотеку jQuery, с которой многие хорошо знакомы. Вместо того, чтобы писать сложные регулярки для получения блоков сайта, с помощью phpQuery мы сможем обращаться к ним с помощью селекторов CSS (если вы плохо владеете ими - изучите их по ссылке).
Сразу предупреждаю, что данная библиотека представляет собой класс и для того, чтобы понять работу с нею, вам нужно владеть хотя бы минимумом знаний по ООП. Если вы его не знаете - изучите его по ссылке ООП в PHP и только потом продолжите чтение.
Начало работы с phpQuery
Официальная документация (англ.) находится по ссылке http://code.google.com/archive/p/phpquery/. Зайдите туда, скачайте эту библиотеку, положите в папку со своим проектом и подключите ее вот так:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
?>
Начало положено, давайте теперь приступим к освоению этой библиотеки.
Основы работы с phpQuery
Работа с phpQuery происходит подобно jQuery (те же методы). Впрочем, даже не зная jQuery вам будет легко разобраться (или же просто возьмите мои заготовки кода и используйте их, особо не вникая).
Итак, начало работы с библиотекой начинается с phpQuery::newDocument($str), где переменная $str - это HTML код для разбора. В результате вернется объект, к которому мы сможем применять определенные методы:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<div id="elem">Текст</div><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
?>
Итак, в переменной $pq лежит объект. У этого объекта есть метод find, который параметром принимает CSS селектор, а делает следующее: ищет внутри HTML кода из $pq элементы подпадающие под этот селектор. Пример:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<div id="elem">Текст</div><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
$elem = $pq->find('#elem');
?>
Сейчас в переменной $elem лежит объект с найденным дивом #elem. У этого объекта есть метод html, который выводит текст найденного элемента (в нашем случае текст дива #elem):
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<div id="elem">Текст</div><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
$elem = $pq->find('#elem');
$text = $elem->html();
var_dump($text);
?>
Кроме метода html есть еще метод text, который делает почти то же самое. Разница: если внутри нашего дива были бы другие теги - метод html вернул бы его текст вместе с этими тегами, а метод text - без них (как будто бы строку обработали функцией strip_tags).
Получение атрибутов
Кроме содержимого тегов, можно также получать содержимое атрибутов. Это делает метод attr, параметром принимающий название атрибута. Давайте получим содержимое href ссылки:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a id="elem" href="http://google.com">Ссылка</a>';
$html = phpQuery::newDocument($str);
$pq = pq($html);
$elem = $pq->find('#elem');
$href = $elem->attr('href');
var_dump($href);
?>
Работа с набором элементов
Предположим, что мы хотим получить не один элемент по его id, а несколько. Давайте попробуем сделать так:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a href="1.html">1</a><a href="2.html">2</a><a href="3.html">3</a>';
$pq = phpQuery::newDocument($str);
$links = $pq->find('a');
$text = $links->html();
var_dump($text);
?>
В результате мы увидим строку '123' - содержимое трех ссылок слитое в одну строку. Врядли мы хотели получить именно это - нам наверняка хотелось бы иметь массив текстов ссылок и массив их href.
Давайте посмотрим на следующий код:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a href="1.html">1</a><a href="2.html">2</a><a href="3.html">3</a>';
$pq = phpQuery::newDocument($str);
$links = $pq->find('a');
?>
В данном случае переменная $links - объект, состоящий из набора других объектов. Такие объекты можно перебирать циклом foreach - и это будет работать. Вот так:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a href="1.html">1</a><a href="2.html">2</a><a href="3.html">3</a>';
$pq = phpQuery::newDocument($str);
$links = $pq->find('a');
foreach ($links as $link) {
}
?>
Внутри цикла переменная $link будет объектом, однако не объектом phpQuery, а объектом DOM. Это значит, что к $link не применимы методы phpQuery (в частности find и html). Чтобы сделать из него объект phpQuery, его следует обернуть в функцию pq (аналог доллара в jQuery).
Давайте сделаем это и заодно накопим тексты ссылок и их href в отдельные массивы:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a href="1.html">1</a><a href="2.html">2</a><a href="3.html">3</a>';
$pq = phpQuery::newDocument($str);
$links = $pq->find('a');
foreach ($links as $link) {
$pqLink = pq($link); //pq делает объект phpQuery
$text[] = $pqLink->html();
$href[] = $pqLink->attr('href');
}
var_dump($text);
var_dump($href);
?>
Удаление
С помощью phpQuery можно удалять по селектору мешающие вам элементы. Это делается с помощью метода remove. Смотрите пример:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<div id="elem">Текст</div><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
$elem = $pq->remove('#elem');
$text = $pq->html();
var_dump($text);
?>
В результате блок <div id="elem">Текст</div> удалится и в строке останется <div>Еще тег</div>.
Оборачивание
Можно также оборачивать элементы с помощью метода wrap. Смотрите пример:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a id="elem">Ссылка</a><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
$elem = $pq->find('#elem')->wrap('<div>');
$text = $pq->html();
var_dump($text);
?>
В результате ссылка обернется в див и станет выглядеть так: <div><a id="elem">Ссылка</a></div>.
Оборачивание
... Смотрите пример:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a id="elem">Ссылка</a><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
$elem = $pq->find('#elem')->wrap('<div class="www">');
$text = $pq->html();
var_dump($text);
?>
В результате ... и станет выглядеть так: <div class="www"><a id="elem">Ссылка</a></div>.
Оборачивание внутри
... Смотрите пример:
<?php
require_once 'phpQuery/phpQuery/phpQuery.php';
$str = '<a id="elem">Ссылка</a><div>Еще тег</div>';
$pq = phpQuery::newDocument($str);
$elem = $pq->find('#elem')->wrapInner('<b>');
$text = $pq->html();
var_dump($text);
?>
В результате ... и станет выглядеть так: <a id="elem">Ссылка</a>.
replaceWith
prev, next, siblings
prevAll, nextAll
prevUntil, nextUntil
parents
псевдоклассы :not, :has, :contains :first, :last, :eq, :empty
Больше возможностей
В общем, phpQuery умеет многое из того, что умеет jQuery и это очень полезно при парсинге. Хорошо владея jQuery, вы сможете понимать и использовать все богатые возможности phpQuery.
Поэтому еще раз рекомендую внимательно изучить учебник jQuery.
Полные возможности phpQuery по манипулированию с DOM смотрите по этой ссылке.
Полные возможности phpQuery по перемещению по дереву DOM смотрите по этой ссылке.
Использование селекторов и псевдоклассов jQuery смотрите по этой ссылке.