Как извлечь img src, title и alt из html с помощью php? - PullRequest
139 голосов
/ 26 сентября 2008

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

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

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

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

Ответы [ 10 ]

241 голосов
/ 30 мая 2010
$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');
}
191 голосов
/ 27 сентября 2008

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

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

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

РЕДАКТИРОВАТЬ: ответ на первый комментарий.

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

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

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

64 голосов
/ 26 сентября 2008

Просто приведу небольшой пример использования 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 более простыми.

8 голосов
/ 26 сентября 2008

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

<?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"
  }
}
5 голосов
/ 27 января 2014

Вы можете использовать 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 голосов
/ 27 сентября 2009

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

foreach( $result[0] as $img_tag)

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

3 голосов
/ 28 сентября 2010

Я использовал 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) за один проход.

1 голос
/ 09 ноября 2011

Вот 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;

}
0 голосов
/ 15 мая 2019

Я прочитал много комментариев на этой странице, которые жалуются на то, что использование парсера 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 = 
---

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

0 голосов
/ 13 ноября 2010

Вот решение, в PHP:

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

$doc= qp($myHtmlDoc);

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

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

}

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

...