>>
Краткий ответ: забудьте про регулярные выражения для HTML/XML
HTML и XML — это нерегулярные языки. Регулярные выражения не могут корректно обрабатывать вложенные теги, атрибуты с кавычками и комментарии. Для надёжного парсинга используйте встроенные библиотеки PHP: DOMDocument + DOMXPath для HTML и SimpleXML для XML.
1. Парсинг HTML с DOMDocument и DOMXPath
Это самый мощный и гибкий способ. DOMDocument загружает HTML и строит DOM-дерево, а DOMXPath позволяет выбирать элементы с помощью XPath-запросов.
<?php
// Загружаем HTML (даже кривой)
$html = file_get_contents('https://example.com');
$dom = new DOMDocument();
// Отключаем строгие ошибки для кривого HTML
libxml_use_internal_errors(true);
$dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
libxml_clear_errors();
// Создаём XPath
$xpath = new DOMXPath($dom);
// Выбираем все ссылки
$links = $xpath->query('//a[@href]');
foreach ($links as $link) {
$href = $link->getAttribute('href');
$text = $link->nodeValue;
echo "Ссылка: $href, Текст: $text\n";
}
// Выбираем заголовки h2 с классом "post-title"
$titles = $xpath->query('//h2[contains(@class, "post-title")]');
foreach ($titles as $title) {
echo "Заголовок: " . $title->nodeValue . "\n";
}
?>
2. Парсинг XML с SimpleXML
Для XML используйте SimpleXML — он проще и быстрее, но требует валидного XML. Если XML кривой — сначала исправьте его через DOMDocument.
<?php
// Пример XML
$xml = '<books>
<book id="1">
<title>PHP для чайников</title>
<author>Иван Петров</author>
</book>
</books>';
$books = simplexml_load_string($xml);
foreach ($books->book as $book) {
$id = (string)$book['id'];
$title = (string)$book->title;
echo "Книга #$id: $title\n";
}
?>
3. XPath — ваш главный инструмент
//div[@class="content"] — все div с классом "content"
//a[contains(@href, "download")] — ссылки, содержащие "download"
//p[position() < 3] — первые два параграфа
//*[@data-id] — любые элементы с атрибутом data-id
4. Обработка кривого HTML и кодировки
Современные сайты часто используют HTML5, который DOMDocument парсит неидеально. Используйте библиотеку masterminds/html5 для корректной работы с HTML5:
composer require masterminds/html5
// Пример с HTML5
use Masterminds\HTML5;
$html5 = new HTML5();
$dom = $html5->loadHTML($html);
$xpath = new DOMXPath($dom);
Для кириллицы всегда указывайте кодировку:
$dom->loadHTML('<meta charset="UTF-8">' . $html);
5. Продвинутые техники
Если нужно парсить много страниц или сложные сайты, используйте DOMCrawler из Symfony (работает поверх DOMDocument):
composer require symfony/dom-crawler
use Symfony\Component\DomCrawler\Crawler;
$crawler = new Crawler($html);
$crawler->filter('a.post-link')->each(function ($node) {
echo $node->text() . ': ' . $node->attr('href') . "\n";
});
Итоговая рекомендация
Для обычного парсинга HTML используйте DOMDocument + DOMXPath (или DOMCrawler). Для XML — SimpleXML. Регулярные выражения оставьте для простых строк, не связанных с HTML/XML. Всегда обрабатывайте ошибки через libxml_use_internal_errors() и не забывайте про кодировку.
<<>>
Альтернативный подход: библиотека PHP Simple HTML DOM Parser
Если вам не хочется разбираться с DOMDocument и XPath, попробуйте библиотеку simplehtmldom. Она предоставляет jQuery-подобный синтаксис для поиска элементов.
composer require simplehtmldom/simplehtmldom
use simplehtmldom\HtmlDocument;
$html = file_get_contents('https://example.com');
$dom = new HtmlDocument();
$dom->load($html);
// Найти все ссылки
foreach ($dom->find('a') as $link) {
echo $link->href . ' - ' . $link->plaintext . "\n";
}
// Найти заголовки по классу
$titles = $dom->find('h2.post-title');
foreach ($titles as $title) {
echo $title->plaintext . "\n";
}
// CSS-селекторы: #id, .class, div > p
$items = $dom->find('div.content ul li');
Плюсы и минусы
Плюсы:
- Простой синтаксис (как в jQuery)
- Хорошо работает с кривым HTML
- Поддерживает CSS-селекторы
Минусы:
- Медленнее, чем DOMDocument
- Не подходит для XML
- Меньше гибкости, чем XPath
Рекомендую использовать эту библиотеку для быстрых прототипов или простых задач. Для серьёзного парсинга (особенно с большими объёмами данных) лучше вернуться к DOMDocument + DOMXPath.