Comment extraire img src, title et alt de html en utilisant php?
je voudrais créer une page où toutes les images qui résident sur mon site sont énumérées avec le titre et la représentation alternative.
j'ai déjà écrit un petit programme pour trouver et charger tous les fichiers HTML, mais maintenant je suis coincé à la façon d'extraire src
, title
et alt
de ce HTML:
<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny" />
je suppose que cela devrait être fait avec un certain regex, mais puisque l'ordre des étiquettes peut varier, et j'ai besoin de tous les, je Je ne sais pas vraiment comment analyser cela d'une manière élégante (je pourrais le faire le char dur par char way, mais c'est douloureux).
21 réponses
EDIT : maintenant que je connais mieux
en utilisant regexp pour résoudre ce genre de problème est une mauvaise idée et sera probablement conduire dans le code Impossible à maintenir et non fiable. Mieux utiliser un HTML parser .
Solution Avec regexp
Dans ce cas, il est préférable de diviser le processus en deux parties :
- obtenir toutes les balise img
- extraire leurs métadonnées
je suppose que votre doc n'est pas XHTML strict Donc vous ne pouvez pas utiliser un analyseur XML. E. G. Avec cette page Web code source:
/* 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)" />
[...]
)
)
nous obtenons alors tous les attributs de la balise img avec une boucle:
$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"
)
)
[..]
)
)
Regexps sont intensif CPU donc vous pouvez vouloir mettre cette page en cache. Si vous n'avez pas de système de cache, vous pouvez modifier le vôtre en utilisant ob_start et en chargeant / sauvegardant à partir d'un fichier texte.
Comment ça marche ?
tout d'abord , nous utilisons preg_ match_ all , une fonction qui obtient chaque chaîne correspondant au motif et l'afficher dans son troisième paramètre.
Les expressions régulières :
<img[^>]+>
nous l'appliquons sur toutes les pages Web html. Il peut être lu comme chaque chaîne qui commence par " <img
", contient non " > " char et se termine par un > .
(alt|title|src)=("[^"]*")
Nous l'appliquons successivement sur chaque balise img. Il peut être lu comme chaque chaîne de caractères commençant par "alt", "titre" ou "src", puis un "=", puis un '" ', un tas de trucs qui ne sont pas '"'et se termine par un '" '. Isoler les sous-chaînes entre () .
enfin, chaque fois que vous voulez traiter avec regexps, il est pratique d'avoir de bons outils pour les tester rapidement. Vérifier ce en ligne regexp tester .
EDIT : réponse au premier commentaire.
il est vrai que je n'ai pas pensé aux (Si tout va bien peu) personnes utilisant des citations simples.
bien, si vous utilisez seulement', remplacez tout le 'par'.
Si vous mélangez les deux. Vous devez d'abord vous gifler :-), puis essayer d'utiliser ("|') à la place ou " et [^ø] pour remplacer [^"].
$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');
}
juste pour donner un petit exemple d'utilisation de la fonctionnalité XML de PHP pour la tâche:
$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'];
}
j'ai utilisé la méthode DOMDocument::loadHTML()
parce que cette méthode peut traiter avec la syntaxe HTML et ne force pas le document d'entrée à être XHTML. Strictement parlant, la conversion en SimpleXMLElement
n'est pas nécessaire - cela rend juste l'utilisation de xpath et les résultats de xpath plus simple.
si C'est XHTML, votre exemple est, vous n'avez besoin que de 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);
?>
sortie:
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"
}
}
le script doit être édité comme ceci
foreach( $result[0] as $img_tag)
parce que preg_match_all renvoie un tableau de tableaux
RE cette solution:
$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');
}
Comment obtenir la balise et l'attribut à partir de plusieurs fichiers/urls?
faire cela n'a pas fonctionné pour moi:
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');
}
}
Vous pouvez utiliser simplehtmldom . La plupart des sélecteurs jQuery sont supportés dans simplehtmldom. Un exemple est donné ci-dessous
// 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>';
Voici une fonction PHP que j'ai cliqué ensemble à partir de toutes les informations ci-dessus pour un but similaire, à savoir le réglage de la largeur de l'étiquette d'image et des propriétés de longueur à la volée ... un peu maladroit, peut-être, mais semble fonctionner de manière fiable:
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;
}
j'ai utilisé preg_match pour le faire.
dans mon cas, j'ai eu une chaîne contenant exactement une étiquette <img>
(et aucun autre markup) que J'ai eu de Wordpress et j'ai essayé d'obtenir l'attribut src
pour que je puisse l'exécuter à travers 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);
Dans le modèle pour saisir le titre ou la touche alt, vous pouvez simplement utiliser $pattern = '/title="([^"]*)"/';
pour saisir le titre ou $pattern = '/title="([^"]*)"/';
pour saisir la touche alt. Malheureusement, mon regex n'est pas assez bon pour saisir tout trois (alt/title/src) avec une passe.
vous pouvez également essayer SimpleXML si le HTML est garanti D'être XHTML - il analysera le markup pour vous et vous serez en mesure d'accéder aux attributs juste par leur nom. (Il y a aussi des bibliothèques DOM si C'est juste HTML et que vous ne pouvez pas dépendre de la syntaxe XML.)
vous pouvez écrire un regexp pour obtenir toutes les étiquettes img ( <img[^>]*>
), puis utiliser simple explode: $res = explode("\"", $tags)
, la sortie sera quelque chose comme ceci:
$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] = "/>";
si vous supprimez la balise <img
avant l'explosion, alors vous obtiendrez un tableau sous la forme de
property=
value
donc l'ordre des propriétés n'est pas pertinent, vous n'utilisez que ce que vous voulez.
Voici la solution, en PHP:
il suffit de télécharger QueryPath, puis faire comme suit:
$doc= qp($myHtmlDoc);
foreach($doc->xpath('//img') as $img) {
$src= $img->attr('src');
$title= $img->attr('title');
$alt= $img->attr('alt');
}
C'est ça, c'est fini !
le code ci-dessous a fonctionné pour moi dans wordpress...
il extrait toutes les sources d'image du code
$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";
}
}
}
santé!
$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);
si vous voulez utiliser regEx pourquoi pas aussi facile que ceci:
preg_match_all('% (.*)=\"(.*)\"%Uis', $code, $matches, PREG_SET_ORDER);
ceci retournera quelque chose comme:
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"
}
}
il y a ma solution pour retrouver uniquement des images à partir du contenu de n'importe quel poste wordpress ou 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);
`
"]+>]+>/)?>"
ceci extraira l'étiquette d'ancrage imbriquée avec l'étiquette d'image
pour un élément, vous pouvez utiliser cette solution miniaturisée en utilisant DOMDocument. Gère les guillemets ' et ' et valide également le html. La meilleure pratique consiste à utiliser des bibliothèques existantes plutôt que votre propre solution en utilisant des expressions régulières.
$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;
Que Diriez-vous d'utiliser une expression régulière pour trouver les étiquettes img (quelque chose comme "<img[^>]*>"
), et puis, pour chaque étiquette img, vous pourriez utiliser une autre expression régulière pour trouver chaque attribut.
peut-être quelque chose comme " ([a-zA-Z]+)=\"([^"]*)\""
pour trouver les attributs, bien que vous pourriez vouloir permettre aux citations n'étant pas là si vous avez affaire à la soupe d'étiquette... Si vous allez avec cela, vous pouvez obtenir le nom du paramètre et la valeur des groupes dans chaque match.
Peut-être que cela vous donnera les bonnes réponses :
<img.*?(?:(?:\s+(src)="([^"]+)")|(?:\s+(alt)="([^"]+)")|(?:\s+(title)="([^"]+)")|(?:\s+[^\s]+))+.*/>