web-dev-qa-db-fra.com

Comment extraire img src, title and alt à partir de html en utilisant php?

J'aimerais créer une page où toutes les images qui résident sur mon site Web sont répertoriées avec un titre et une représentation alternative.

J'ai déjà écrit un petit programme pour trouver et charger tous les fichiers HTML, mais je ne sais plus comment extraire src, title et alt de ce code HTML:

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

Je suppose que cela devrait être fait avec une regex, mais comme l’ordre des tags peut varier et que j’ai besoin de tous, je ne sais pas vraiment comment analyser cela de manière élégante (je pourrais le faire avec hard char par char façon, mais c'est douloureux).

140
Sam

EDIT: maintenant que je sais mieux

Utiliser regexp pour résoudre ce genre de problème est ne mauvaise idée et mènera probablement à un code non maintenable et peu fiable. Mieux vaut utiliser un analyseur HTML .

Solution avec regexp

Dans ce cas, il est préférable de scinder le processus en deux parties:

  • obtenir tous les tags img
  • extraire leurs métadonnées

Je supposerai que votre document n'est pas xHTML strict, vous ne pouvez donc pas utiliser un analyseur XML. PAR EXEMPLE. avec le code source de cette page Web:

/* 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)" />

[...]
        )

)

Ensuite, nous obtenons 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"
                )

        )

   [..]
        )

)

Les expressions régulières nécessitent beaucoup de temps de traitement, vous voudrez peut-être mettre cette page en cache. Si vous n'avez pas de système de cache, vous pouvez modifier votre propre en utilisant ob_start et en chargeant/sauvegardant depuis un fichier texte.

Comment ça marche?

Premièrement, nous utilisons preg_ match_all , une fonction qui récupère chaque chaîne correspondant au modèle et le renvoie 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 un caractère non ">" et se termine par un> .

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

Nous l'appliquons successivement sur chaque tag img. Il peut être lu comme chaque chaîne commençant par "alt", "title" ou "src", puis un "=", puis un "", un tas de choses qui ne sont pas " "'et se termine par un" ". Isolez les sous-chaînes entre () .

Enfin, chaque fois que vous voulez gérer les expressions rationnelles, il est utile d’avoir de bons outils pour les tester rapidement. Vérifiez ceci testeur d'expressions rationnelles en ligne .

EDIT: répondez au premier commentaire.

Il est vrai que je n’ai pas pensé aux personnes (espérons-le rares) utilisant des guillemets simples.

Eh bien, si vous utilisez seulement ', remplacez simplement tous les "par".

Si vous mélangez les deux. D'abord, vous devriez vous gifler :-), puis essayez d'utiliser ("| ') à la place ou" et [^ ø] pour remplacer [^ "].

191
e-satis
$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');
}
242
karim

Juste pour donner un petit exemple d'utilisation de la fonctionnalité XML de PHP pour cette 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() car cette méthode peut gérer 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 - elle simplifie l'utilisation de xpath et des résultats de xpath.

64
Stefan Gehrig

Si vous utilisez l'exemple XHTML, vous n'avez besoin que de XML simple.

<?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"
  }
}
8
DreamWerx

Le script doit être édité comme ceci

foreach( $result[0] as $img_tag)

parce que preg_match_all retourne un tableau de tableaux

5
Bakudan

Vous pouvez utiliser simplehtmldom . La plupart des sélecteurs jQuery sont pris en charge 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>'; 
5
Nauphal

J'ai utilisé preg_match pour le faire.

Dans mon cas, j’avais une chaîne contenant exactement une balise <img> (et aucune autre balise) que j’avais obtenue de Wordpress et j’essayais d’obtenir l’attribut src afin que je puisse exécutez-le à 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 permettant de saisir le titre ou l'alt, vous pouvez simplement utiliser $pattern = '/title="([^"]*)"/'; pour saisir le titre ou $pattern = '/title="([^"]*)"/'; pour saisir l'alt. Malheureusement, ma regex n'est pas assez bonne pour saisir les trois (alt/title/src) en un seul passage.

3
WNRosenberg

Voici une fonction PHP J'ai mis en parallèle toutes les informations ci-dessus dans un but similaire, à savoir ajuster les propriétés de largeur et de longueur de balise d'image à 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;

}
1
John Daliani

Voici la solution, en PHP:

Il suffit de télécharger QueryPath, puis procédez comme suit:

$doc= qp($myHtmlDoc);

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

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

}

Ça y est, vous avez terminé!

0
Xavier

J'ai lu les nombreux commentaires sur cette page qui se plaignent que l'utilisation d'un analyseur dom est une surcharge inutile. Cela coûte peut-être plus cher qu'un simple appel regex, mais le PO a déclaré qu'il n'y avait aucun contrôle sur l'ordre des attributs dans les balises img. Ce fait conduit à une convolution inutile du motif regex. De plus, l'utilisation d'un analyseur dom offre les avantages supplémentaires de lisibilité, de maintenabilité et de connaissance de dom (regex n'est pas sensible à dom).

J'aime regex et je réponds à beaucoup de questions sur les regex, mais quand on traite avec du HTML valide, il y a rarement une bonne raison de regex avec un analyseur.

Dans la démonstration ci-dessous, voyez comme DOMDocument est facile et propre à gérer les attributs de balises img dans n’importe quel ordre, avec une combinaison de guillemets (et pas de guillemets du tout). Notez également que les balises sans attribut ciblé ne perturbent pas du tout - une chaîne vide est fournie en tant que valeur.

Code: ( Demo )

$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";
}

Sortie:

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 = 
---

L'utilisation de cette technique dans un code professionnel vous laissera un script clair, moins de problèmes et plus de collègues qui souhaiteraient que vous travailliez ailleurs.

0
mickmackusa