Как извлечь 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" />Я думаю, это должно быть сделано с некоторым регулярным выражением, но поскольку порядок тегов может отличаться, и мне нужны все из них, я действительно не знаю, как разобрать это в элегантный способ (я мог бы сделать это жестким способом char by char, но это больно).
21 ответов:
EDIT: теперь, когда я знаю лучше
используя регулярное выражение для решения такого рода проблемы плохая идея и, скорее всего, приведет к недостижимому и ненадежному коду. Лучше использовать анализатор 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, a функция, которая получает каждую строку, соответствующую шаблону, и выводит ее в свой третий параметр.
в регулярках :
<img[^>]+>мы применяем его на всех веб-страницах html. Его можно прочитать как каждая строка, которая начинается с "
<img", содержит non " > " char и заканчивается на A >.(alt|title|src)=("[^"]*")мы применяем его последовательно на каждом теге img. Его можно прочитать как каждая строка, начинающаяся с "alt", "title" или "src", затем"=", затем"", куча вещей это не '"'и заканчивается на'"'. Изолируйте подстроки между ().
наконец, каждый раз, когда вы хотите иметь дело с регулярными выражениями, удобно иметь хорошие инструменты для быстрого их тестирования. Проверьте это онлайн тестер регулярных выражений.
изменить: ответ на первый комментарий.
это правда, что я не думал о (надеюсь, мало) людей, использующих одинарные кавычки.
Ну, если вы используете только ', просто замените все "на'.
если вы смешиваете оба. Сначала вы должны ударить себя : -), затем попробуйте использовать ( " | ') вместо или " и [^ø] заменить [^"].
$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'); }
просто чтобы дать небольшой пример использования функциональности 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 более простыми.
Если это 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" } }
скрипт должен быть отредактирован следующим образом
foreach( $result[0] as $img_tag)потому что preg_match_all возвращает массив массивов
RE это решение:
$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'); } }
вы можете использовать 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>';
вот функция 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; }
я использовал 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) с одним проходом.
вы также можете попробовать SimpleXML, если HTML гарантированно будет XHTML - он будет анализировать разметку для вас, и вы сможете получить доступ к атрибутам только по их имени. (Есть также библиотеки DOM, если это просто HTML, и вы не можете зависеть от синтаксиса XML.)
вы можете написать регулярное выражение, чтобы получить все теги 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таким образом, порядок свойств не имеет значения, вы используете только то, что вам понравится.
вот решение, в PHP:
просто загрузите QueryPath, а затем выполните следующие действия:
$doc= qp($myHtmlDoc); foreach($doc->xpath('//img') as $img) { $src= $img->attr('src'); $title= $img->attr('title'); $alt= $img->attr('alt'); }вот и все, вы сделали !
приведенный ниже код работал для меня в 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"; } } }ура!
$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);
Если вы хотите использовать регулярное выражение, почему бы не так просто, как это:
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" } }
есть мое решение для получения изображения только от содержания любой пост в 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);`
для одного элемента вы можете использовать это уменьшенное решение с помощью 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;
Как насчет использования регулярного выражения для поиска тегов img (что-то вроде
"<img[^>]*>"), а затем для каждого тега img вы можете использовать другое регулярное выражение для поиска каждого атрибута.может быть, что-то вроде
" ([a-zA-Z]+)=\"([^"]*)\""чтобы найти атрибуты, хотя вы можете захотеть, чтобы кавычки не были там, если вы имеете дело с супом тегов... Если вы пошли с этим, вы можете получить имя параметра и значение из групп в каждом матче.
может быть, это даст вам правильные ответы :
<img.*?(?:(?:\s+(src)="([^"]+)")|(?:\s+(alt)="([^"]+)")|(?:\s+(title)="([^"]+)")|(?:\s+[^\s]+))+.*/>
Comments