【问题标题】:Using regular expressions to extract the first image source from html codes?使用正则表达式从 html 代码中提取第一个图像源?
【发布时间】:2010-11-14 20:35:15
【问题描述】:

我想知道如何实现。

假设:有很多包含表格、div、图像等的 html 代码。

问题:如何获得所有出现的匹配项。此外,具体来说,我怎样才能获得 img 标签源(src = ?)。

示例:

<img src="http://example.com/g.jpg" alt="" />

在这种情况下,我如何打印出http://example.com/g.jpg。我想假设我提到的 html 代码中还有其他标签,并且可能不止一个图像。是否可以在 html 代码中包含所有图像源的数组?

我知道这可以通过正则表达式来实现,但我无法掌握它。

非常感谢任何帮助。

【问题讨论】:

标签: php html regex


【解决方案1】:

虽然正则表达式可以很好地完成各种各样的任务,但我发现它在解析 HTML DOM 时通常不够用。 HTML 的问题在于您的文档结构非常多变,以至于很难准确(准确地说,我的意思是 100% 成功率且没有误报)提取标签。

我建议您使用 DOM 解析器,例如 SimpleHTML 并像这样使用它:

function get_first_image($html) {
    require_once('SimpleHTML.class.php')

    $post_html = str_get_html($html);

    $first_img = $post_html->find('img', 0);

    if($first_img !== null) {
        return $first_img->src;
    }

    return null;
}

有些人可能认为这有点矫枉过正,但最终,它会更容易维护,并允许更多的可扩展性。例如,使用 DOM 解析器,我也可以获取 alt 属性。

可以设计一个正则表达式来实现相同的目标,但会受到限制,它会强制alt 属性位于src 之后或相反,克服这个限制会增加更多的复杂性到正则表达式。

此外,请考虑以下事项。要使用正则表达式正确匹配 &lt;img&gt; 标记并仅获取 src 属性(在第 2 组中捕获),您需要以下正则表达式:

<\s*?img\s+[^>]*?\s*src\s*=\s*(["'])((\\?+.)*?)\1[^>]*?>

再一次,如果出现以下情况,上述操作可能会失败:

  • 属性或标签名称大写且未使用 i 修饰符。
  • src 属性周围不使用引号。
  • src 之后的另一个属性在其值的某处使用了&gt; 字符。
  • 其他一些我没有预见到的原因。

同样,不要使用正则表达式来解析 dom 文档。


编辑:如果你想要所有图片:

function get_images($html){
    require_once('SimpleHTML.class.php')

    $post_dom = str_get_dom($html);

    $img_tags = $post_dom->find('img');

    $images = array();

    foreach($img_tags as $image) {
        $images[] = $image->src;
    }

    return $images;
}

【讨论】:

  • 我觉得这种方式非常好。无论属性顺序如何,这都会起作用吗?我的意思是 src 或 SRC,可以吗?即使我放了 alt 和 title 标签..?此代码将在客户端服务器上运行,因此我需要确保无论他们以何种方式放置 src,它都会被提取。非常感谢您快速而完整的回答。
  • @Ahmad Fouad: 正确,使用 DOM 解析器无论属性顺序和大小写如何都可以工作。
  • 为什么你的正则表达式中的所有非贪婪的“\s*?”?普通的贪婪“\s*”不是更有效率吗?
  • @Kip: 因为你不希望它贪婪。
  • 非常好。我想我会采用这个解决方案,因为发布正则表达式的用户发布了各种公式并假设 src 将以特定的方式和顺序输入..如果客户以非传统方式输入 src,这将变得无用:(谢谢这么多!
【解决方案2】:

用这个,效果更佳:

preg_match_all('/<img [^>]*src=["|\']([^"|\']+)/i', $html, $matches);
foreach ($matches[1] as $key=>$value) {
    echo $value."<br>";
}

例子:

$html = '
<ul>     
  <li><a target="_new" href="http://www.manfromuranus.com">Man from Uranus</a></li>       
  <li><a target="_new" href="http://www.thevichygovernment.com/">The Vichy Government</a></li>      
  <li><a target="_new" href="http://www.cambridgepoetry.org/">Cambridge Poetry</a></li>      
  <img width="190" height="197" border="0" align="right" alt="upload.jpg" title="upload.jpg" class="noborder" src="value1.jpg" />
  <li><a href="http://www.verot.net/pretty/">Electronaut Records</a></li>      
  <img width="190" height="197" border="0" align="right" alt="upload.jpg" title="upload.jpg" class="noborder" src="value2.jpg" />
  <li><a target="_new" href="http://www.catseye-crew.com">Catseye Productions</a></li>     
  <img width="190" height="197" border="0" align="right" alt="upload.jpg" title="upload.jpg" class="noborder" src="value3.jpg" />
</ul>
<img width="190" height="197" border="0" align="right" alt="upload.jpg" title="upload.jpg" class="noborder" src="res/upload.jpg" />
  <li><a target="_new" href="http://www.manfromuranus.com">Man from Uranus</a></li>       
  <li><a target="_new" href="http://www.thevichygovernment.com/">The Vichy Government</a></li>      
  <li><a target="_new" href="http://www.cambridgepoetry.org/">Cambridge Poetry</a></li>      
  <img width="190" height="197" border="0" align="right" alt="upload.jpg" title="upload.jpg" class="noborder" src="value4.jpg" />
  <li><a href="http://www.verot.net/pretty/">Electronaut Records</a></li>      
  <img src="value5.jpg" />
  <li><a target="_new" href="http://www.catseye-crew.com">Catseye Productions</a></li>     
  <img width="190" height="197" border="0" align="right" alt="upload.jpg" title="upload.jpg" class="noborder" src="value6.jpg" />
';   
preg_match_all('/<img .*src=["|\']([^"|\']+)/i', $html, $matches);
foreach ($matches[1] as $key=>$value) {
    echo $value."<br>";
} 

输出:

value1.jpg
value2.jpg
value3.jpg
res/upload.jpg
value4.jpg
value5.jpg
value6.jpg

【讨论】:

  • regex 假定 html 将适合 regex 模式。即使您有一个简单而完美的表达式来查找数据,您仍然依赖于一种模式匹配语言,该语言会返回它找到的内容,而无需与原始数据/字符串进行任何形式的集成。您的正则表达式就像一个魅力,但是使用“说”html/xml 的扩展可以帮助我在晚上睡觉,更不用说我可以修改它来做其他事情,而不必担心我的修改会导致更多的问题,然后它会修复。
  • 这段代码获取插入到代码中的最新图片的src。我尝试在代码中添加 3 个图像标签,它只收集一个图像(一个源).. 可以稍微调整一下以显示数组中的所有图像源吗?
  • 艾哈迈德,你试过我的回答了吗?我认为 inakibt 的答案只返回第一个值,因为它有 $matches[1],但是自从我使用 preg_match_all 确定如何修改它已经有一段时间了。 DOM 和 simplexml 是更好解决方案的另一个原因。
  • 另外,Ahmad,我的回答只需要为您的 PHP 配置 simpleXML 和 DOM,大多数 PHP5 安装都是默认的。无需下载并包含 simpleHTMLDOM 插件。只需 4 行代码,您就可以得到您要查找的数组。
  • 我可能会考虑正则表达式,因为我有很多客户仍在使用 php 4。那会很痛苦
【解决方案3】:

这对我有用:

preg_match('@<img.+src="(.*)".*>@Uims', $html, $matches);
$src = $matches[1];

【讨论】:

  • 我认为您的三个点需要替换为 [^>],否则您最终可能会匹配页面上第一个和最后一个 img 标记之间的所有内容
  • 我相信这会错过 b/c 的单引号
  • 其实中间点应该是 [^>"] 我认为
【解决方案4】:

我假设你所有的 src= 在 url 周围都有 "

<img[^>]+src=\"([^\"]+)\"

此处发布的其他答案对您的代码做出了其他假设

【讨论】:

  • 一些流行的 cms 会这样做 scr='...' 甚至像这样的空格 src = '...'
【解决方案5】:

我同意安德鲁·摩尔的观点。使用 DOM 会好很多。 HTML DOM 图像集合将返回给您对所有图像对象的引用。

假设在你的标题中,

<script type="text/javascript">
    function getFirstImageSource()
    {
        var img = document.images[0].src;
        return img;
    }
</script>

然后在你的身体里,

<script type="text/javascript">
  alert(getFirstImageSource());
</script>

这将返回第一个图像源。您还可以沿着(在头部)的行中循环遍历它们

function getAllImageSources()
    {
        var returnString = "";
        for (var i = 0; i < document.images.length; i++)
        {
            returnString += document.images[i].src + "\n"
        }
        return returnString;
    }

(在正文中)

<script type="text/javascript">
  alert(getAllImageSources());
</script>

如果您使用 JavaScript 来执行此操作,请记住,您不能在标头中的图像集合中循环运行您的函数。换句话说,你不能做这样的事情,

<script type="text/javascript">
    function getFirstImageSource()
    {
        var img = document.images[0].src;
        return img;
    }
    window.onload = getFirstImageSource;  //bad function

</script>

因为这行不通。执行标头时图像尚未加载,因此您将得到空结果。

希望这可以在某种程度上有所帮助。如果可能,我会使用 DOM。你会发现很多工作已经为你完成了。

【讨论】:

    【解决方案6】:

    我不知道您是否必须使用正则表达式来获得结果。如果没有,您可以尝试 simpleXML 和 XPath,这对于您的目标会更加可靠:

    首先,将 HTML 导入到 DOM 文档对象中。如果您遇到错误,请关闭此部分的错误,然后确保将其重新打开:

     $dom = new DOMDocument();
     $dom -> loadHTMLFile("filename.html");
    

    接下来,将 DOM 导入 simpleXML 对象,如下所示:

     $xml = simplexml_import_dom($dom);
    

    现在您可以使用几种方法将所有图像元素(及其属性)放入一个数组中。 XPath 是我更喜欢的一个,因为我在用它遍历 DOM 时运气更好:

     $images = $xml -> xpath('//img/@src');
    

    现在可以将此变量视为图像 URL 的数组:

     foreach($images as $image) {
        echo '<img src="$image" /><br />
        ';
      }
    

    Presto,你所有的图像,没有脂肪。

    这是上述内容的非注释版本:


     $dom = new DOMDocument();
     $dom -> loadHTMLFile("filename.html");
    
     $xml = simplexml_import_dom($dom);
    
     $images = $xml -> xpath('//img/@src');
    
     foreach($images as $image) {
        echo '<img src="$image" /><br />
        ';
      }
    

    【讨论】:

      【解决方案7】:

      我真的认为你不能用正则表达式预测所有的情况。

      最好的方法是使用带有PHP5 class DOMDocument 和xpath 的DOM。这是做你想做的最干净的方式。

      $dom = new DOMDocument();
      $dom->loadHTML( $htmlContent );
      $xml = simplexml_import_dom($dom);
      $images = $xml -> xpath('//img/@src');
      

      【讨论】:

        【解决方案8】:

        你可以试试这个:

        preg_match_all("/<img\s+src=\"(.+)\"/i", $html, $matches);
        foreach ($matches as $key=>$value) {
            echo $key . ", " . $value . "<br>";
        }
        

        【讨论】:

          【解决方案9】:

          由于您不担心验证 HTML,您可以尝试先在文本上使用 strip_tags() 以清除大部分内容。

          然后你可以搜索像

          这样的表达式
          "/\<img .+ \/\>/i"
          

          反斜杠转义特殊字符,如 、/。 .+ 坚持在 img 标签内有 1 个或多个任意字符 您可以通过将括号括起来来捕获表达式的一部分。例如(.+) 捕获 img 标签的中间部分。

          当您决定要特别捕捉中间的哪个部分时,您可以将 (.+) 修改为更具体的内容。

          【讨论】:

            【解决方案10】:
            <?php    
            /* PHP Simple HTML DOM Parser @ http://simplehtmldom.sourceforge.net */
            
            require_once('simple_html_dom.php');
            
            $html = file_get_html('http://example.com');
            $image = $html->find('img')[0]->src;
            
            echo "<img src='{$image}'/>"; // BOOM!
            

            PHP Simple HTML DOM Parser 只需几行代码即可完成这项工作。

            【讨论】:

              猜你喜欢
              • 2012-10-21
              • 2021-10-29
              • 2023-03-18
              • 1970-01-01
              • 2017-11-09
              • 1970-01-01
              • 2010-12-21
              • 2015-01-24
              • 1970-01-01
              相关资源
              最近更新 更多