2015-12-12 3 views
0

У меня есть веб-страница, например, http://example.com/some-page. Если я передам этот URL-адрес моей функции PHP, он должен захватить заголовок и содержимое страницы. Я попытался захватить название:Как получить название и содержимое веб-страницы

function page_title($url) { 
    $page = @file_get_contents($url); 
    if (preg_match('~<h1 class="page-title">(.*)<\/h1>~is', $page, $matches)) { 
     return $matches[0]; 
    } 
} 

echo page_title('http://example.com/some-page'); 

В чем моя ошибка?

+0

Возможно, вы захотите использовать DOM-парсер для этого. Может работать лучше, чем 'preg_'. – Rasclatt

+0

http://ahoj.io/parsing-html-pages-using-xpath – pavlovich

+0

Укажите, пожалуйста, неожиданный результат или сообщение об ошибке. Удалите '@', с помощью которого вы в настоящее время пытаетесь подавить сообщения об ошибках. – trincot

ответ

0

Ваша функция фактически работает почти. Я хотел бы предложить решение DOM парсер (смотри ниже), но прежде чем делать, что я укажу несколько слабых мест в регулярном выражении и код:

  • группа (.*) захвата жаден, то он будет ловить строку до тех пор, пока не будет закрыто </h1>, даже при разрыве линии (из-за модификатора s). Поэтому, если ваш документ имеет несколько меток h1, он будет захватывать до последнего! Вы можете исправить это, сделав его ленивым захватом: (.*?)

  • Фактическая страница может иметь другие метки, такие как span, внутри названия. Вы можете улучшить регулярное выражение, чтобы исключить любые теги, которые окружают ваш заголовок, но для этой цели PHP имеет функцию strip_tags.

  • Убедитесь, что содержимое файла было фактически восстановлено; ошибка может помешать правильному изъятию, или ваш сервер может не разрешить такой поиск. И поскольку вы подавляете ошибки с использованием префикса @, вы, возможно, пропустите их. Я бы предложил удалить @. Вы также можете проверить возвращаемое значение для false.
  • Вы уверены, что хотите добавить тег H1? На странице часто присутствует специальный тег title.

Вышеуказанные улучшения даст вам этот код:

function page_title($url) { 
    $page = file_get_contents($url); 
    if ($page===false) { 
     echo "Failed to retrieve $url"; 
    } 
    if (preg_match('~<h1 class="page-title">(.*?)<\/h1>~is', $page, $matches)) { 
     return strip_tags($matches[0]); 
    } 
} 

Хотя это работает, вы рано или поздно столкнетесь с документом, который имеет дополнительное пространство в h1 тега, или имеет другой атрибут, прежде class, или имеет более одного стиля css и т. Д., Что приводит к сбою. Следующее регулярное выражение будет иметь дело с некоторыми из этих проблем:

~<h1\s+class\s*=\s*"([^" ]*)?page-title([^"]*)?"[^>]*>(.*?)<\/h1\s*>~is 

... но все же атрибут class должен перед любыми другими атрибутами, и его значение должно быть заключено в двойные кавычки. Также это можно решить, но регулярное выражение станет монстром.

DOM-путь

Регулярные выражения не являются идеальным способом для извлечения содержимого из HTML. Вот альтернативная функция, основанная на DOM разборе:

function xpage_title($url) { 
    // Create a new DOM Document to hold our webpage structure 
    $xml = new DOMDocument(); 

    // Load the url's contents into the DOM, ignore warnings 
    libxml_use_internal_errors(true); 
    $success = $xml->loadHTMLFile($url); 
    libxml_use_internal_errors(false); 
    if (!$success) { 
     echo "Failed to open $url."; 
     return; 
    } 

    // Find first h1 with class 'page-title' and return it's text contents 
    foreach($xml->getElementsByTagName('h1') as $h1) { 
     // Does it have the desired class? 
     if (in_array('page-title', explode(" ", $h1->getAttribute('class')))) { 
      return $h1->textContent; 
     } 
    } 
} 

выше может быть еще улучшен путем использования DOMXpath.

EDIT

Вы упоминали в комментариях вы на самом деле не хотите, содержимое тега H1, поскольку он содержит больше текста, чем вы хотите.

Тогда вы могли бы прочитать title тег и содержимое по тегу: article

function page_title_and_content($url) { 
    $page = file_get_contents($url); 
    if ($page===false) { 
     echo "Failed to retrieve $url"; 
    } 
    // PHP 5.4: $result = (object) ["title" => null, "content" => null]; 
    $result = new stdClass(); 
    $result->title = null; 
    $result->content = null; 
    if (preg_match('~\<title\>(.*?)\<\/title\>~is', $page, $matches)) { 
     $result->title = $matches[1]; 
    } 
    if (preg_match('~<article>(.*)<\/article>~is', $page, $matches)) { 
     $result->content = $matches[1]; 
    } 
    return $result; 
} 

$result = page_title_and_content('http://www.example.com/example'); 
echo "title: " . $result->title . "<br>"; 
echo "content: <br>" . $result->content . "<br>"; 

Приведенный выше код будет возвращать объект с двумя свойствами: название и содержание. Обратите внимание, что свойство будет иметь HTML-теги с потенциально изображениями и т. Д. Если вам не нужны теги, примените strip_tags.

+0

отлично, но ответ подобен этому 2015_NOV_ALL_PEOPLE - Неделя глобального предпринимательства: имеет ли ваш бизнес все, что нужно? Я хочу только «Глобальная неделя предпринимательства: имеет ли ваш бизнес все, что нужно?» поэтому я думаю, что внутренний диапазон inserting – fahim

+0

Тег H1 содержит «2015_NOV_ALL_PEOPLE - ...», но в вашем вопросе вы сказали, что хотите содержимое тега H1. Если вам нужен заголовок, вы должны просто прочитать тег заголовка. – trincot

+0

ОК работает. спросите меня, если я хочу получить заголовок и содержимое страницы, а затем код регулярных выражений? – fahim

Смежные вопросы