Как извлечь img src, title и alt из html с помощью php?

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

Я уже написал небольшую программу для поиска и загрузки всех файлов HTML, но теперь я застрял в том, как извлечь src, title и alt из этого HTML:

<img src = "/image/fluffybunny.jpg" title = "Harvey the bunny" alt = "a cute little fluffy bunny" />

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
154
1
319 613
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Просто чтобы дать небольшой пример использования функциональности PHP XML для этой задачи:

$doc=new DOMDocument();
$doc->loadHTML("<html><body>Test<br><img src=\"myimage.jpg\" title=\"title\" alt=\"alt\"></body></html>");
$xml=simplexml_import_dom($doc); // just to make xpath more simple
$images=$xml->xpath('//img');
foreach ($images as $img) {
    echo $img['src'] . ' ' . $img['alt'] . ' ' . $img['title'];
}

Я использовал метод DOMDocument::loadHTML(), потому что этот метод может справиться с HTML-синтаксисом и не заставляет входной документ быть XHTML. Строго говоря, преобразование в SimpleXMLElement не обязательно - это просто упрощает использование xpath и результаты xpath.

Конечно, этот подход очень прост, но кто-то может захотеть использовать знак @ при вызове метода loadHTML (@ $ doc-> loadHTML), поскольку это предотвратит появление предупреждений.

Alex Polo 16.08.2010 14:25

Вызовите эту функцию заранее, чтобы корректно обрабатывать ошибки: libxml_use_internal_errors( true );. Вы также можете перебрать эти ошибки XML с помощью libxml_get_errors().

Matt 13.01.2012 21:10

Если это XHTML, ваш пример, вам нужен только simpleXML.

<?php
$input = '<img src = "/image/fluffybunny.jpg" title = "Harvey the bunny" alt = "a cute little fluffy bunny"/>';
$sx = simplexml_load_string($input);
var_dump($sx);
?>

Выход:

object(SimpleXMLElement)#1 (1) {
  ["@attributes"]=>
  array(3) {
    ["src"]=>
    string(22) "/image/fluffybunny.jpg"
    ["title"]=>
    string(16) "Harvey the bunny"
    ["alt"]=>
    string(26) "a cute little fluffy bunny"
  }
}
Ответ принят как подходящий

Обновлено: теперь, когда я знаю лучше

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

Решение с регулярным выражением

В этом случае лучше разделить процесс на две части:

  • получить все теги img
  • извлекать их метаданные

Я предполагаю, что ваш документ не является строгим по xHTML, поэтому вы не можете использовать синтаксический анализатор XML. НАПРИМЕР. с исходным кодом этой веб-страницы:

/* preg_match_all match the regexp in all the $html string and output everything as 
an array in $result. "i" option is used to make it case insensitive */

preg_match_all('/<img[^>]+>/i',$html, $result); 

print_r($result);
Array
(
    [0] => Array
        (
            [0] => <img src = "/Content/Img/stackoverflow-logo-250.png" width = "250" height = "70" alt = "logo link to homepage" />
            [1] => <img class = "vote-up" src = "/content/img/vote-arrow-up.png" alt = "vote up" title = "This was helpful (click again to undo)" />
            [2] => <img class = "vote-down" src = "/content/img/vote-arrow-down.png" alt = "vote down" title = "This was not helpful (click again to undo)" />
            [3] => <img src = "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt = "gravatar image" />
            [4] => <img class = "vote-up" src = "/content/img/vote-arrow-up.png" alt = "vote up" title = "This was helpful (click again to undo)" />

[...]
        )

)

Затем мы получаем все атрибуты тега img с помощью цикла:

$img = array();
foreach( $result as $img_tag)
{
    preg_match_all('/(alt|title|src)=("[^"]*")/i',$img_tag, $img[$img_tag]);
}

print_r($img);

Array
(
    [<img src = "/Content/Img/stackoverflow-logo-250.png" width = "250" height = "70" alt = "logo link to homepage" />] => Array
        (
            [0] => Array
                (
                    [0] => src = "/Content/Img/stackoverflow-logo-250.png"
                    [1] => alt = "logo link to homepage"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                )

            [2] => Array
                (
                    [0] => "/Content/Img/stackoverflow-logo-250.png"
                    [1] => "logo link to homepage"
                )

        )

    [<img class = "vote-up" src = "/content/img/vote-arrow-up.png" alt = "vote up" title = "This was helpful (click again to undo)" />] => Array
        (
            [0] => Array
                (
                    [0] => src = "/content/img/vote-arrow-up.png"
                    [1] => alt = "vote up"
                    [2] => title = "This was helpful (click again to undo)"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                    [2] => title
                )

            [2] => Array
                (
                    [0] => "/content/img/vote-arrow-up.png"
                    [1] => "vote up"
                    [2] => "This was helpful (click again to undo)"
                )

        )

    [<img class = "vote-down" src = "/content/img/vote-arrow-down.png" alt = "vote down" title = "This was not helpful (click again to undo)" />] => Array
        (
            [0] => Array
                (
                    [0] => src = "/content/img/vote-arrow-down.png"
                    [1] => alt = "vote down"
                    [2] => title = "This was not helpful (click again to undo)"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                    [2] => title
                )

            [2] => Array
                (
                    [0] => "/content/img/vote-arrow-down.png"
                    [1] => "vote down"
                    [2] => "This was not helpful (click again to undo)"
                )

        )

    [<img src = "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt = "gravatar image" />] => Array
        (
            [0] => Array
                (
                    [0] => src = "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
                    [1] => alt = "gravatar image"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                )

            [2] => Array
                (
                    [0] => "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
                    [1] => "gravatar image"
                )

        )

   [..]
        )

)

Регулярные выражения интенсивно используют ЦП, поэтому вы можете захотеть кэшировать эту страницу. Если у вас нет системы кеширования, вы можете настроить свою собственную, используя ob_start и загружая / сохраняя из текстового файла.

Как это работает?

Во-первых, мы используем preg_ match_ all, функцию, которая получает каждую строку, соответствующую шаблону, и выводит ее в третьем параметре.

Регулярные выражения:

<img[^>]+>

Мы применяем его на всех веб-страницах HTML. Его можно читать как каждая строка, которая начинается с "<img", содержит символы, отличные от ">", и заканчивается символом>.

(alt|title|src)=("[^"]*")

Применяем его последовательно к каждому тегу img. Его можно читать как каждая строка, начинающаяся с "alt", "title" или "src", затем "=", затем "" ', множество вещей, которые не являются' "'и заканчиваются'" '. Изолируйте под- строки между ().

Наконец, каждый раз, когда вы хотите иметь дело с регулярными выражениями, полезно иметь хорошие инструменты для их быстрого тестирования. Отметьте это онлайн-тестер регулярных выражений.

Обновлено: ответ на первый комментарий.

Это правда, что я не думал о людях (надеюсь, немногих), использующих одинарные кавычки.

Что ж, если вы используете только ', просто замените все «на».

Если смешать оба. Сначала вы должны дать себе пощечину :-), затем попробуйте использовать ("| ') вместо или" и [^ ø] для замены [^ "].

Проблема только в одинарных кавычках: <img src = 'picture.jpg' /> не будет работать, регулярное выражение ожидает "все время

Sam 01.10.2008 19:18

Тре мой друг. Я добавил примечание об этом. Спасибо.

e-satis 04.10.2008 15:20

Я бы НЕ рекомендовал прокручивать вниз (хорошо, прокрутите, чтобы проверить это): хотя код кажется простым и поэтому соблазнительным для людей, DOMDocument имеет оооочень много накладных расходов, когда вы просто хотите получить атрибуты из тега. ..

patrick 08.11.2014 11:59

Это решение хорошо, если: вы не знаете тега HTML для синтаксического анализа, у вас есть 1 строка HTML и требуется 1-2 атрибута. Загрузка DOMDoc требует больших затрат памяти, что бесполезно, если вы не разбираете весь документ.

viion 27.02.2015 01:36

Это не распространяется на alt=foo или alt='foo'.

mgutt 19.03.2015 22:50

Скрипт надо редактировать вот так

foreach( $result[0] as $img_tag)

потому что preg_match_all возвращает массив массивов

$url = "http://example.com";

$html = file_get_contents($url);

$doc = new DOMDocument();
@$doc->loadHTML($html);

$tags = $doc->getElementsByTagName('img');

foreach ($tags as $tag) {
       echo $tag->getAttribute('src');
}

Мне любопытно, работает ли это быстрее, чем preg_match

321zeno 02.11.2011 13:07

Мне нравится, как легко это читать! xpath и regex тоже работают, но 18 месяцев спустя их уже не так легко читать.

Dylan Valade 16.11.2011 08:02

Хотя это коротко и просто, это огромная трата ресурсов ... это означает, что использование DOMDocument для извлечения атрибутов из тега - это много (!!!) накладных расходов.

patrick 08.11.2014 12:00

как ограничить, пример максимум 10 изображений ??

vaneayoung 22.01.2016 20:05

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

Angry 84 15.11.2016 03:44

это должен быть предпочтительный ответ, простой и БЕЗ РЕГЕКСА. не используйте регулярные выражения люди. здесь вы не пишете детерминированный автоматический парсер

clockw0rk 11.02.2021 18:41

Я использовал для этого preg_match.

В моем случае у меня была строка, содержащая ровно один тег <img> (и никакой другой разметки), которую я получил из Wordpress, и я пытался получить атрибут src, чтобы я мог запустить его через timthumb.

// get the featured image
$image = get_the_post_thumbnail($photos[$i]->ID);

// get the src for that image
$pattern = '/src = "([^"]*)"/';
preg_match($pattern, $image, $matches);
$src = $matches[1];
unset($matches);

В шаблоне для захвата заголовка или альта вы можете просто использовать $pattern = '/title = "([^"]*)"/';, чтобы захватить заголовок, или $pattern = '/title = "([^"]*)"/';, чтобы захватить альт. К сожалению, мое регулярное выражение недостаточно хорошо, чтобы захватить все три (alt / title / src) за один проход.

не будет работать, если атрибуты тега img заключены в одинарные кавычки; <img src='image.png'>

numediaweb 25.11.2014 15:51

Вы не должны отвечать «в вашем случае», вы должны ответить на точный / точный вопрос ОП.

mickmackusa 15.05.2019 17:00

Вот решение на PHP:

Просто скачайте QueryPath и сделайте следующее:

$doc= qp($myHtmlDoc);

foreach($doc->xpath('//img') as $img) {

   $src= $img->attr('src');
   $title= $img->attr('title');
   $alt= $img->attr('alt');

}

Вот и все, готово!

Неа. Это не РЕШЕНИЕ.

nwalke 06.04.2013 09:05

Вот функция PHP, которую я ковылял из всей вышеупомянутой информации для той же цели, а именно для настройки ширины и длины свойств тега изображения на лету ... возможно, немного неуклюже, но, похоже, работает надежно:

function ReSizeImagesInHTML($HTMLContent,$MaximumWidth,$MaximumHeight) {

// find image tags
preg_match_all('/<img[^>]+>/i',$HTMLContent, $rawimagearray,PREG_SET_ORDER); 

// put image tags in a simpler array
$imagearray = array();
for ($i = 0; $i < count($rawimagearray); $i++) {
    array_push($imagearray, $rawimagearray[$i][0]);
}

// put image attributes in another array
$imageinfo = array();
foreach($imagearray as $img_tag) {

    preg_match_all('/(src|width|height)=("[^"]*")/i',$img_tag, $imageinfo[$img_tag]);
}

// combine everything into one array
$AllImageInfo = array();
foreach($imagearray as $img_tag) {

    $ImageSource = str_replace('"', '', $imageinfo[$img_tag][2][0]);
    $OrignialWidth = str_replace('"', '', $imageinfo[$img_tag][2][1]);
    $OrignialHeight = str_replace('"', '', $imageinfo[$img_tag][2][2]);

    $NewWidth = $OrignialWidth; 
    $NewHeight = $OrignialHeight;
    $AdjustDimensions = "F";

    if ($OrignialWidth > $MaximumWidth) { 
        $diff = $OrignialWidth-$MaximumHeight; 
        $percnt_reduced = (($diff/$OrignialWidth)*100); 
        $NewHeight = floor($OrignialHeight-(($percnt_reduced*$OrignialHeight)/100)); 
        $NewWidth = floor($OrignialWidth-$diff); 
        $AdjustDimensions = "T";
    }

    if ($OrignialHeight > $MaximumHeight) { 
        $diff = $OrignialHeight-$MaximumWidth; 
        $percnt_reduced = (($diff/$OrignialHeight)*100); 
        $NewWidth = floor($OrignialWidth-(($percnt_reduced*$OrignialWidth)/100)); 
        $NewHeight= floor($OrignialHeight-$diff); 
        $AdjustDimensions = "T";
    } 

    $thisImageInfo = array('OriginalImageTag' => $img_tag , 'ImageSource' => $ImageSource , 'OrignialWidth' => $OrignialWidth , 'OrignialHeight' => $OrignialHeight , 'NewWidth' => $NewWidth , 'NewHeight' => $NewHeight, 'AdjustDimensions' => $AdjustDimensions);
    array_push($AllImageInfo, $thisImageInfo);
}

// build array of before and after tags
$ImageBeforeAndAfter = array();
for ($i = 0; $i < count($AllImageInfo); $i++) {

    if ($AllImageInfo[$i]['AdjustDimensions'] == "T") {
        $NewImageTag = str_ireplace('width = "' . $AllImageInfo[$i]['OrignialWidth'] . '"', 'width = "' . $AllImageInfo[$i]['NewWidth'] . '"', $AllImageInfo[$i]['OriginalImageTag']);
        $NewImageTag = str_ireplace('height = "' . $AllImageInfo[$i]['OrignialHeight'] . '"', 'height = "' . $AllImageInfo[$i]['NewHeight'] . '"', $NewImageTag);

        $thisImageBeforeAndAfter = array('OriginalImageTag' => $AllImageInfo[$i]['OriginalImageTag'] , 'NewImageTag' => $NewImageTag);
        array_push($ImageBeforeAndAfter, $thisImageBeforeAndAfter);
    }
}

// execute search and replace
for ($i = 0; $i < count($ImageBeforeAndAfter); $i++) {
    $HTMLContent = str_ireplace($ImageBeforeAndAfter[$i]['OriginalImageTag'],$ImageBeforeAndAfter[$i]['NewImageTag'], $HTMLContent);
}

return $HTMLContent;

}

Вы можете использовать простой. Большинство селекторов jQuery поддерживаются в simplehtmldom. Пример приведен ниже

// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br>';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br>'; 

Я прочитал множество комментариев на этой странице, в которых жалуются, что использование парсера dom не требует дополнительных затрат. Что ж, это может быть дороже, чем простой вызов регулярного выражения, но OP заявил, что нет никакого контроля над порядком атрибутов в тегах img. Этот факт приводит к ненужной свертке шаблона регулярного выражения. Помимо этого, использование анализатора dom обеспечивает дополнительные преимущества читабельности, удобства обслуживания и осведомленности о dom (регулярное выражение не поддерживает dom).

Мне нравятся регулярные выражения, и я отвечаю на множество вопросов о регулярных выражениях, но при работе с допустимым HTML редко есть веская причина для регулярного выражения через синтаксический анализатор.

В демонстрации ниже вы увидите, насколько просто и чисто DOMDocument обрабатывает атрибуты тега img в любом порядке со смесью кавычек (и вообще без кавычек). Также обратите внимание, что теги без целевого атрибута вообще не мешают - в качестве значения предоставляется пустая строка.

Код: (Демо)

$test = <<<HTML
<img src = "/image/fluffybunny.jpg" title = "Harvey the bunny" alt = "a cute little fluffy bunny" />
<img src='/image/pricklycactus.jpg' title='Roger the cactus' alt='a big green prickly cactus' />
<p>This is irrelevant text.</p>
<img alt = "an annoying white cockatoo" title = "Polly the cockatoo" src = "/image/noisycockatoo.jpg">
<img title=something src=somethingelse>
HTML;

libxml_use_internal_errors(true);  // silences/forgives complaints from the parser (remove to see what is generated)
$dom = new DOMDocument();
$dom->loadHTML($test);
foreach ($dom->getElementsByTagName('img') as $i => $img) {
    echo "IMG#{$i}:\n";
    echo "\tsrc = " , $img->getAttribute('src') , "\n";
    echo "\ttitle = " , $img->getAttribute('title') , "\n";
    echo "\talt = " , $img->getAttribute('alt') , "\n";
    echo "---\n";
}

Выход:

IMG#0:
    src = /image/fluffybunny.jpg
    title = Harvey the bunny
    alt = a cute little fluffy bunny
---
IMG#1:
    src = /image/pricklycactus.jpg
    title = Roger the cactus
    alt = a big green prickly cactus
---
IMG#2:
    src = /image/noisycockatoo.jpg
    title = Polly the cockatoo
    alt = an annoying white cockatoo
---
IMG#3:
    src = somethingelse
    title = something
    alt = 
---

Использование этой техники в профессиональном коде оставит вам чистый сценарий, меньше проблем, с которыми придется бороться, и меньше коллег, которые хотели бы, чтобы вы работали где-то еще.

Другие вопросы по теме