Получение заголовка страницы в PHP: варианты реализации

Раздел: Веб-разработка -> Метаданные

Методы получения заголовка страницы в PHP

Задача получения тега из HTML-документа часто возникает при разработке парсеров, анализе сайтов или создании метаданных. Рассмотрим несколько подходов.</p><div class="rbase"><h3>Основное решение с использованием DOMDocument</h3><p>Класс DOMDocument позволяет загрузить HTML и извлечь заголовок надёжно, не полагаясь на регулярные выражения.</p><pre class="ex_c"><code>$url = 'https://example.com'; $html = @file_get_contents($url); if ($html === false) { die('Ошибка получения содержимого'); } $dom = new DOMDocument(); libxml_use_internal_errors(true); $dom->loadHTML($html); libxml_clear_errors(); $titleNode = $dom->getElementsByTagName('title')->item(0); $title = $titleNode ? $titleNode->nodeValue : 'Заголовок не найден'; echo $title;</code></pre><p class="mb-5 me-5 p-2 bg-ltgreen text-success rounded d-inline-flex t-small"><i class="bi bi-play-fill"></i><a href="/v/php-get-title/#main" class="px-1">Php get title </a> (получение заголовка страницы в php)</p><p class="fw-bold">Пояснение:</p><ul><li><code>file_get_contents</code> получает HTML-код.</li><li><code>DOMDocument::loadHTML</code> парсит строку.</li><li><code>getElementsByTagName('title')</code> возвращает коллекцию; берётся первый элемент.</li><li>Обработка ошибок парсинга через <code>libxml_use_internal_errors</code>.</li></ul><div class="rproblem"><p class="fw-bold">Возможные проблемы:</p><ul><li>Неверная кодировка (например, windows-1251). Решение: перед загрузкой преобразовать строку через <code>mb_convert_encoding</code>.</li><li>Таймаут при получении контента. Решение: использовать cURL с таймаутом.</li><li>Отсутствие тега <code><title></code> – проверка на <code>null</code>.</li></ul></div></div><div class="rvar"><h4 class="rvop">Как быстро извлечь заголовок без загрузки DOM?</h4><p>Вариант с регулярным выражением. Подходит для простых случаев, когда структура HTML не содержит вложенных сложностей.</p><pre class="ex_c"><code>$html = file_get_contents('https://example.com'); preg_match('/<title>([^<]*)<\/title>/i', $html, $matches); $title = $matches[1] ?? 'Не найден'; echo $title;</code></pre><p>Регулярка ищет содержимое между <title> и . Проблема: если заголовок содержит другие теги или переносы строк, выражение не сработает. Решение: использовать флаг s (PCRE_DOTALL) и учитывать возможные пробелы.

Ошибка: при многострочном заголовке или вложениях. Корректная регулярка: /]*>(.*?)<\/title>/si. Используется нежадный квантификатор и s для точки.

Как получить заголовок с сайта, требующего обработку редиректов и заголовков?

cURL даёт контроль над запросом: можно установить таймаут, User-Agent, следовать редиректам.

$ch = curl_init('https://example.com');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_USERAGENT => 'Mozilla/5.0',
]);
$html = curl_exec($ch);
curl_close($ch);
$dom = new DOMDocument();
@$dom->loadHTML($html);
$title = $dom->getElementsByTagName('title')->item(0);
echo $title ? $title->nodeValue : 'Не найден';

Цель: обеспечить надёжное получение контента даже при редиректах и блокировках.

Ошибки: сертификаты SSL, пустой ответ. Для игнорирования SSL можно добавить CURLOPT_SSL_VERIFYPEER => false (не рекомендуется на production).

Как упростить парсинг при помощи сторонней библиотеки?

Библиотека Simple HTML DOM Parser предоставляет простой синтаксис для поиска элементов.

include 'simple_html_dom.php';
$html = file_get_html('https://example.com');
$title = $html->find('title', 0)->plaintext;
echo $title;

Плюс: интуитивно понятные методы. Минус: библиотека не обновляется, может быть медленной.

Как извлечь title из локального файла на сервере?

Если страница уже сохранена, достаточно указать путь к файлу.

$html = file_get_contents('/path/to/page.html');
$dom = new DOMDocument();
$dom->loadHTML($html);
$title = $dom->getElementsByTagName('title')->item(0)->nodeValue;

Аналогично для строки.

Какие меры предосторожности при недоступности сайта?

Важно обрабатывать таймауты, ошибки соединения и пустые ответы. Пример с cURL и проверкой:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$html = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (!$html || $httpCode != 200) {
    $title = 'Не удалось получить страницу';
} else {
    $dom = new DOMDocument();
    @$dom->loadHTML($html);
    $title = $dom->getElementsByTagName('title')->item(0)->nodeValue ?? 'Нет title';
}

Рекомендуется также устанавливать обработчик исключений.

Типичные ошибки и их решение

  • Неверная кодировка: заголовок отображается кракозябрами. Решение – принудительно установить кодировку перед парсингом: $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'auto'); или $dom->loadHTML('<?xml encoding="utf-8" ?>' . $html);
  • Многострочный заголовок: регулярка без флага s не находит. Решение – использовать DOMDocument, который корректно обрабатывает переносы.
  • Отсутствие тега <title>: всегда проверять результат на null или искать альтернативы (meta og:title).
  • SSL-ошибки: на этапе разработки можно отключить проверку сертификата, в production настроить CA-сертификаты.
  • Ограничение памяти: при загрузке больших страниц увеличить memory_limit или использовать потоковую загрузку.

Расширенные примеры с пояснениями

Детальные сценарии для надёжного получения заголовка.

Пример 1: Корректная обработка кодировки с DOMDocument

Пример
$url = 'https://example.com';
$html = @file_get_contents($url);
if ($html === false) {
    exit('Не удалось получить HTML');
}
$encoding = mb_detect_encoding($html, ['UTF-8', 'Windows-1251', 'KOI8-R'], true);
if ($encoding && $encoding != 'UTF-8') {
    $html = mb_convert_encoding($html, 'UTF-8', $encoding);
}
$dom = new DOMDocument();
@$dom->loadHTML($html);
$title = $dom->getElementsByTagName('title')->item(0);
$titleText = $title ? $title->nodeValue : 'Заголовок не определён';
echo $titleText;
Пример вывода: "Добро пожаловать на Example.com" (в правильной кодировке)

Пример 2: cURL с полным контролем и обработкой редиректов

Пример
$url = 'https://example.com';
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_MAXREDIRS => 5,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; MyBot/1.0)',
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_CAINFO => '/path/to/cacert.pem',
]);
$html = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($html === false || $info['http_code'] !== 200) {
    $error = curl_error($ch);
    echo "Ошибка: $error";
} else {
    $dom = new DOMDocument();
    @$dom->loadHTML($html);
    $title = $dom->getElementsByTagName('title')->item(0);
    echo $title ? $title->nodeValue : 'Не найден';
}
Вывод: успешный заголовок или сообщение об ошибке.

Пример 3: Циклический обход нескольких страниц с логированием

Пример
$urls = ['https://site1.com', 'https://site2.com', 'https://site3.com'];
foreach ($urls as $url) {
    $html = @file_get_contents($url, false, stream_context_create([
        'http' => ['timeout' => 5, 'user_agent' => 'MyParser/1.0']
    ]));
    if ($html === false) {
        error_log("Не удалось загрузить $url");
        continue;
    }
    $dom = new DOMDocument();
    @$dom->loadHTML($html);
    $titleNode = $dom->getElementsByTagName('title')->item(0);
    $title = $titleNode ? trim($titleNode->nodeValue) : 'N/A';
    echo "$url: $title\n";
}
https://site1.com: Первый сайт
https://site2.com: Второй сайт
https://site3.com: N/A

Пример 4: Использование библиотеки Guzzle для асинхронного получения

Пример
use GuzzleHttp\Client;
$client = new Client(['timeout' => 10]);
$promises = [];
$urls = ['https://site1.com', 'https://site2.com'];
foreach ($urls as $url) {
    $promises[$url] = $client->getAsync($url)->then(function ($response) {
        $html = (string)$response->getBody();
        $dom = new DOMDocument();
        @$dom->loadHTML($html);
        $title = $dom->getElementsByTagName('title')->item(0);
        return $title ? $title->nodeValue : 'нет';
    });
}
$results = GuzzleHttp\Promise\settle($promises)->wait();
foreach ($results as $url => $result) {
    echo "$url: " . ($result['value'] ?? 'ошибка') . "\n";
}
(пример вывода при успешном выполнении)

Пример 5: Обработка заголовка с пробелами и специальными символами через DOMXPath

Пример
$html = '   Привет, мир! "Тест"   ';
$dom = new DOMDocument();
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$titles = $xpath->query('//title/text()');
$title = '';
if ($titles->length > 0) {
    $title = trim($titles->item(0)->nodeValue);
}
echo htmlspecialchars($title);
Привет, мир! "Тест"

Примечание:

Получение заголовка страницы в PHP - comments

En
Php get title (php)