Ваша функция фактически работает почти. Я хотел бы предложить решение 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
.
Возможно, вы захотите использовать DOM-парсер для этого. Может работать лучше, чем 'preg_'. – Rasclatt
http://ahoj.io/parsing-html-pages-using-xpath – pavlovich
Укажите, пожалуйста, неожиданный результат или сообщение об ошибке. Удалите '@', с помощью которого вы в настоящее время пытаетесь подавить сообщения об ошибках. – trincot