【问题标题】:Grabbing the href attribute of an A element获取 A 元素的 href 属性
【发布时间】:2011-04-18 18:03:24
【问题描述】:

试图在页面上找到链接。

我的正则表达式是:

/<a\s[^>]*href=(\"\'??)([^\"\' >]*?)[^>]*>(.*)<\/a>/

但似乎失败了

<a title="this" href="that">what?</a>

我将如何更改我的正则表达式以处理未放在 a 标记中的 href?

【问题讨论】:

    标签: php html dom


    【解决方案1】:

    Reliable Regex for HTML are difficult。以下是使用DOM 的方法:

    $dom = new DOMDocument;
    $dom->loadHTML($html);
    foreach ($dom->getElementsByTagName('a') as $node) {
        echo $dom->saveHtml($node), PHP_EOL;
    }
    

    上面将找到并输出$html 字符串中所有A 元素的"outerHTML"

    获取节点的所有文本值,您可以这样做

    echo $node->nodeValue; 
    

    检查href 属性是否存在,您可以这样做

    echo $node->hasAttribute( 'href' );
    

    获取你会做的href属性

    echo $node->getAttribute( 'href' );
    

    更改你会做的href属性

    $node->setAttribute('href', 'something else');
    

    删除你会做的href属性

    $node->removeAttribute('href'); 
    

    也可以直接用XPath查询href属性

    $dom = new DOMDocument;
    $dom->loadHTML($html);
    $xpath = new DOMXPath($dom);
    $nodes = $xpath->query('//a/@href');
    foreach($nodes as $href) {
        echo $href->nodeValue;                       // echo current attribute value
        $href->nodeValue = 'new value';              // set new attribute value
        $href->parentNode->removeAttribute('href');  // remove attribute
    }
    

    另见:

    附注:我确定这是重复的,您可以find the answer somewhere in here

    【讨论】:

    • 可靠的正则表达式解析 HTML 本质上是不可能的,即使 HTML 不是常规语言。
    【解决方案2】:

    我同意 Gordon 的观点,您必须使用 HTML 解析器来解析 HTML。但如果你真的想要一个正则表达式,你可以试试这个:

    /^<a.*?href=(["\'])(.*?)\1.*$/
    

    这匹配字符串开头的&lt;a,然后是任意数量的任意字符(非贪婪).*?,然后是href=,然后是由"'包围的链接

    $str = '<a title="this" href="that">what?</a>';
    preg_match('/^<a.*?href=(["\'])(.*?)\1.*$/', $str, $m);
    var_dump($m);
    

    输出:

    array(3) {
      [0]=>
      string(37) "<a title="this" href="that">what?</a>"
      [1]=>
      string(1) """
      [2]=>
      string(4) "that"
    }
    

    【讨论】:

    • 仅供参考:如果我们在包含许多 a 元素的文本中搜索而不是表达式 (.*?) 是错误的
    【解决方案3】:

    您要查找的模式是链接锚模式,例如(某物):

    $regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";
    

    【讨论】:

    • 锚属性多了怎么办?
    【解决方案4】:

    你为什么不直接匹配

    "<a.*?href\s*=\s*['"](.*?)['"]"
    
    <?php
    
    $str = '<a title="this" href="that">what?</a>';
    
    $res = array();
    
    preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res);
    
    var_dump($res);
    
    ?>
    

    然后

    $ php test.php
    array(2) {
      [0]=>
      array(1) {
        [0]=>
        string(27) "<a title="this" href="that""
      }
      [1]=>
      array(1) {
        [0]=>
        string(4) "that"
      }
    }
    

    有效。我刚刚删除了第一个捕获括号。

    【讨论】:

    • 我建议使用preg_match_all("/&lt;a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);,以便在使用foreach($res as $key =&gt; $val){echo $val[1]}时正确捕获所有href值
    【解决方案5】:

    对于仍然无法使用 SimpleXML 轻松快速地获得解决方案的人

    $a = new SimpleXMLElement('<a href="www.something.com">Click here</a>');
    echo $a['href']; // will echo www.something.com
    

    它对我有用

    【讨论】:

      【解决方案6】:

      快速测试:&lt;a\s+[^&gt;]*href=(\"\'??)([^\1]+)(?:\1)&gt;(.*)&lt;\/a&gt; 似乎可以解决问题,第一个匹配是 " 或 ',第二个匹配 'href' 值 'that',第三个匹配 'what?'。

      我将“/”的第一个匹配项留在其中的原因是您可以稍后使用它来反向引用它以关闭“/”,所以它是相同的。

      查看实时示例:http://www.rubular.com/r/jsKyK2b6do

      【讨论】:

      • @bergin 请说明,什么不起作用?我从您的测试 HTML 中的 href 获得了确切的值。你期望这不会做什么?我看到您使用不同的站点进行测试,在那里我也成功地从您的示例中获得了“href”值。 myregextester.com/?r=d966dd6b
      【解决方案7】:

      我不确定您在这里要做什么,但如果您要验证链接,请查看 PHP 的 filter_var()

      如果您确实需要使用正则表达式,请查看此工具,它可能会有所帮助: http://regex.larsolavtorvik.com/

      【讨论】:

        【解决方案8】:

        使用您的正则表达式,我对其进行了一些修改以满足您的需要。

        &lt;a.*?href=("|')(.*?)("|').*?&gt;(.*)&lt;\/a&gt;

        我个人建议你使用HTML Parser

        编辑:测试

        【讨论】:

        • 使用 myregextester.com - 抱歉,没有找到链接
        • 它说:没有匹配。检查分隔符碰撞。
        • 你能告诉我要匹配的文本吗?我使用:&lt;a title="this" href="that"&gt;what?&lt;/a&gt;
        • 我对这种误解的猜测是,bergin 没有在 Ruel 的答案中添加模式定界符,该答案不使用模式定界符。如果没有模式分隔符,正则表达式引擎将假定 &lt; 是起始分隔符,&gt; 是结束分隔符(当然这些字符出现在模式中,所以你有“冲突”。
        【解决方案9】:

        以下内容对我有用,并返回锚标记的 hrefvalue

        preg_match_all("'\<a.*?href=\"(.*?)\".*?\>(.*?)\<\/a\>'si", $html, $match);
        if($match) {
            foreach($match[0] as $k => $e) {
                $urls[] = array(
                    'anchor'    =>  $e,
                    'href'      =>  $match[1][$k],
                    'value'     =>  $match[2][$k]
                );
            }
        }
        

        名为$urls 的多维数组现在包含易于使用的关联子数组。

        【讨论】:

        • 我发现单引号不是模式分隔符的最佳选择——它经常用于字符串的实际引用,以至于我的眼睛没有立即将其注册为分隔符。最常见的分隔符可能是/,但由于您的模式使用了/,我可能会推荐~。因为分隔符不是/,所以您不需要在模式中转义/。您也不需要转义 &lt;&gt;,因为它们对正则表达式引擎没有特殊意义。
        • 喜欢这个"\&lt;a.*?href=\"(.*?)\".*?&gt;(.*?)&lt;/a&gt;\si" @mickmackusa ?
        • 没有。您不能使用反斜杠作为分隔符。使用正斜杠。
        【解决方案10】:

        preg_match_all("/(]>)(.?)()/", $contents, $impmatches, PREG_SET_ORDER);

        经过测试,它会从任何 html 代码中获取所有标签。

        【讨论】:

          猜你喜欢
          • 2017-10-04
          • 2011-08-15
          • 1970-01-01
          • 2017-05-28
          • 2012-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多