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


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

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

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

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

Author: Andy Lester, 2008-09-26

21 answers

РЕДАКТИРОВАТЬ: теперь, когда я знаю лучше

Использование регулярного выражения для решения такого рода проблем является плохой идеей и, скорее всего, приведет к недостижимому и ненадежному коду. Лучше использовать синтаксический анализатор 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", затем "=", затем "", кучу вещей, которые не являются """ и заканчиваются """. Изолируйте подстроки между ().

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

ПРАВКА: ответ на первый комментарий.

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

Ну, если вы используете только ', просто замените все "на".

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

 184
Author: e-satis, 2017-05-23 12:03:05
$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');
}
 234
Author: karim, 2010-12-18 02:32:24

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

$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.

 64
Author: Stefan Gehrig, 2008-09-26 10:40:36

Используйте xpath.

Для php вы можете использовать simplexml или domxml

См. также этот вопрос

 13
Author: yann.kmm, 2017-05-23 12:03:05

Если это 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"
  }
}
 8
Author: DreamWerx, 2008-09-26 10:30:44

Сценарий должен быть отредактирован следующим образом

foreach( $result[0] as $img_tag)

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

 5
Author: Bakudan, 2010-12-18 02:32:50

ПОВТОРИТЕ это решение:

    $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');
    }

Как получить тег и атрибут из нескольких файлов/URL-адресов?

Это не сработало для меня:

    foreach (glob("path/to/files/*.html") as $html) {

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

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

      foreach ($tags as $tag) {
         echo $tag->getAttribute('src');
      } 
    } 
 5
Author: user1312079, 2012-08-17 07:02:18

Вы можете использовать simplehtmldom. Большинство селекторов 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>'; 
 5
Author: Nauphal, 2014-01-27 07:24:20

Вот функция 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;

}
 2
Author: John Daliani, 2011-11-09 07:57:35

Для этого я использовал 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);

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

 1
Author: Jazzerus, 2010-09-28 16:59:34

Вы также можете попробовать SimpleXML, если HTML гарантированно будет XHTML - он проанализирует разметку для вас, и вы сможете получить доступ к атрибутам только по их имени. (Существуют также библиотеки DOM, если это просто HTML, и вы не можете зависеть от синтаксиса XML.)

 0
Author: Borek Bernard, 2008-09-26 08:35:35

Вы можете написать регулярное выражение, чтобы получить все теги img (<img[^>]*>), а затем использовать простое разложение: $res = explode("\"", $tags), вывод будет примерно таким:

$res[0] = "<img src=";
$res[1] = "/image/fluffybunny.jpg";
$res[2] = "title=";
$res[3] = "Harvey the bunny";
$res[4] = "alt=";
$res[5] = "a cute little fluffy bunny";
$res[6] = "/>";

Если вы удалите тег <img до разнесения, то вы получите массив в виде

property=
value

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

 0
Author: Biri, 2008-09-26 08:49:26

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

Просто скачайте QueryPath, а затем выполните следующие действия:

$doc= qp($myHtmlDoc);

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

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

}

Вот и все, с тобой покончено!

 0
Author: Xavier, 2010-11-13 13:52:25

Приведенный ниже код работал для меня в wordpress...

Он извлекает все источники изображений из кода

$search = "any html code with image tags";

preg_match_all( '/src="([^"]*)"/', $search, $matches);

if ( isset( $matches ) )
{
    foreach ($matches as $match) 
    {
        if(strpos($match[0], "src")!==false)
        {
            $res = explode("\"", $match[0]);
            $image = parse_url($res[1], PHP_URL_PATH);
            $xml .= " <image:image>\n";
            $xml .= " <image:loc>".home_url().$image."</image:loc>\n";
            $xml .= " <image:caption>".htmlentities($title)."</image:caption>\n";
            $xml .= " <image:license>".home_url()."</image:license>\n";
            $xml .= " </image:image>\n";
        }
    }
}

Ура!

 0
Author: foxybagga, 2011-02-24 08:38:24
$content =  "<img src='http://google.com/2af5e6ae749d523216f296193ab0b146.jpg' width='40' height='40'>";
$image   =  preg_match_all('~<img rel="imgbot" remote="(.*?)" width="(.*?)" height="(.*?)" linktext="(.*?)" linkhref="(.*?)" src="(.*?)" />~is', $content, $matches);
 0
Author: phpdev, 2012-10-05 15:26:41

Если вы хотите использовать регулярное выражение, почему бы не сделать это так просто:

preg_match_all('% (.*)=\"(.*)\"%Uis', $code, $matches, PREG_SET_ORDER);

Это вернет что-то вроде:

array(2) {
    [0]=>
    array(3) {
        [0]=>
        string(10) " src="abc""
        [1]=>
        string(3) "src"
        [2]=>
        string(3) "abc"
    }
    [1]=>
    array(3) {
        [0]=>
        string(10) " bla="123""
        [1]=>
        string(3) "bla"
        [2]=>
        string(3) "123"
    }
}
 0
Author: Nico Knoll, 2015-02-17 20:08:41

Есть мое решение для восстановления только изображений из содержимого любого поста в wordpress или html-контенте. `

$content = get_the_content();
$count = substr_count($content, '<img');
$start = 0;
for ($i=0;$i<$count;$i++) {
  if ($i == 0){
    $imgBeg = strpos($content, '<img', $start);
    $post = substr($content, $imgBeg);
  } else {
    $imgBeg = strpos($post, '<img', $start);
    $post = substr($post, $imgBeg-2);
  }
  $imgEnd = strpos($post, '>');
  $postOutput = substr($post, 0, $imgEnd+1);
  $postOutput = preg_replace('/width="([0-9]*)" height="([0-9]*)"/', '',$postOutput);
  $image[$i] = $postOutput;
  $start= $imgEnd + 1;
} 
print_r($image);

`

 0
Author: Jainty Sarraff, 2016-02-09 07:56:48
"]+>]+>/)?>"


это приведет к извлечению тега привязки, вложенного в тег изображения

 -1
Author: Muhammad Irfan, 2010-04-29 06:31:55

Для одного элемента вы можете использовать это уменьшенное решение с помощью DOMDocument. Обрабатывает кавычки "и", а также проверяет html. Рекомендуется использовать существующие библиотеки, а не собственное решение с использованием регулярных выражений.

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

$doc = new DOMDocument();
@$doc->loadHTML($html);
$attributeValue = @$doc->documentElement->firstChild->firstChild->attributes->getNamedItem($attribute)->value;

echo $attributeValue;
 -1
Author: Wizzard, 2017-03-31 10:30:38

Как насчет использования регулярного выражения для поиска тегов img (что-то вроде "<img[^>]*>"), а затем для каждого тега img вы можете использовать другое регулярное выражение для поиска каждого атрибута.

Может быть, что-то вроде " ([a-zA-Z]+)=\"([^"]*)\"", чтобы найти атрибуты, хотя вы, возможно, захотите разрешить отсутствие кавычек, если вы имеете дело с супом из тегов... Если бы вы пошли с этим, вы могли бы получить имя и значение параметра из групп внутри каждого соответствия.

 -2
Author: MB., 2008-09-26 08:47:22

Возможно, это даст вам правильные ответы:

<img.*?(?:(?:\s+(src)="([^"]+)")|(?:\s+(alt)="([^"]+)")|(?:\s+(title)="([^"]+)")|(?:\s+[^\s]+))+.*/> 
 -2
Author: Levi, 2011-03-09 13:05:33