如何使用php从HTML提取img src,标题和alt?

时间:2020-03-06 14:46:19  来源:igfitidea点击:

我想创建一个页面,其中列出我网站上的所有图像,并附带标题和替代表示。

我已经写了一个小程序来查找和加载所有HTML文件,但是现在我被困在如何从此HTML中提取" src"," title"和" alt"的方法:

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

我想应该使用一些正则表达式来完成此操作,但是由于标记的顺序可能会有所不同,而且我需要所有这些正则表达式,所以我真的不知道如何以一种优雅的方式解析它(我可以通过char方式,但这很痛苦)。

解决方案

如果HTML被保证为XHTML,我们也可以尝试SimpleXML,它将为我们解析标记,并且我们可以仅通过属性名称访问属性。 (如果只有HTML并且我们不能依赖XML语法,那么也有DOM库。)

如何使用正则表达式查找img标签(类似于"" <img [^>] *>"`),然后对于每个img标签,可以使用另一个正则表达式查找每个属性。

也许类似"''([(a-zA-Z] +)= "([[^"] *)""`之类的东西来查找属性,但是如果我们要处理的话,可能希望不使用引号带有标签汤...如果这样做,则可以从每个匹配项的组中获取参数名称和值。

我们可以编写一个正则表达式来获取所有img标签(&lt;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] = "/>";

如果在爆炸之前删除&lt;img标签,则会得到一个数组,形式为

property=
value

因此属性的顺序无关紧要,我们只需使用所需的内容即可。

使用xpath。

对于php,我们可以使用simplexml或者domxml

另请参阅此问题

给出一个使用PHP的XML功能完成任务的小例子:

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

编辑:现在我知道了

使用正则表达式解决此类问题不是一个好主意,并且很可能导致无法维护和不可靠的代码。最好使用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"
                )

        )

   [..]
        )

)

正则表达式占用大量CPU,因此我们可能需要缓存此页面。如果没有缓存系统,则可以使用ob_start进行调整,并从文本文件加载/保存。

这些东西是如何工作的?

首先,我们使用preg_ match_ all,该函数获取与模式匹配的每个字符串,并将其输出到它的第三个参数中。

正则表达式:

<img[^>]+>

我们将其应用于所有html网页。可以将其读取为以"&lt;img"开头,包含非">"字符并以>结尾的每个字符串。

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

我们先后将其应用于每个img标签。可以将其读取为以" alt"," title"或者" src"开头的每个字符串,然后是" =",然后是"",一堆不是""并以""结尾的东西隔离()之间的子字符串。

最后,每次我们想处理正则表达式时,都拥有快速测试它们的好工具非常方便。检查此在线正则表达式测试器。

编辑:回答第一个评论。

的确,我没有考虑过使用单引号的人(希望很少)。

好吧,如果仅使用',只需将所有的'替换为'。

如果我们混合两者。首先,我们应该打自己一巴掌:-),然后尝试使用(" |')代替,或者使用"和[^?]代替[^"]。

必须像这样编辑脚本

`foreach($ result [0] as $ img_tag)

因为preg_match_all返回数组数组

"]+>]+>/)?>"

这将提取嵌套在图像标签中的锚标签

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

我用preg_match做到了。

就我而言,我有一个字符串,其中包含一个刚从Wordpress获得的&lt;img>标签(没有其他标记),并且我试图获取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)。

这是PHP中的解决方案:

只需下载QueryPath,然后执行以下操作:

$doc= qp($myHtmlDoc);

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

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

}

就是这样,我们完成了!