PHP - 解析html以从" a"中检索href。标记在另一个" a"标签

时间:2015-10-19 02:09:45

标签: php html regex href domdocument

我已经搜索了几个小时(不应该有任何重复),并尝试使用正则表达式(正则表达式)和DOM文档的许多不同方法,但没有成功。

非标准html代码如何显示:

<a class="SOMECLASS" href="javascript:__FUNCTION(SOME_HREF_INSIDE)" onclick="SOME_JS_FUNCTION();" id="SOME_ID" style="SOME_STYLE">
    <a href="SOME_URL_3">SOME TEXT</a>
</a>

现在的问题是我试图获取网址&#34; SOME_URL_3&#34;当使用正则表达式或DOMdocument进行解析时,pasing会在遇到第一个href时立即停止。当然作为第二个&#34; a&#34; tag是第一个的一部分,解析器只将其视为一个。

我发现浏览器在解析时似乎会自动将标记分开,如下所示:

之前:

<a href="SOME_URL">
    <a href="SOME_URL_2">
    </a>
</a>

后:

<a href="SOME_URL">
</a>
<a href="SOME_URL_2">
</a>

我无法使用php复制此浏览器行为。

我尝试过的更接近工作:

$dom = new DOMDocument();
@$dom->loadHTML($result);

foreach($dom->getElementsByTagName('a') as $link) { 
    $href_count = 0;
    $attrs = array();

    for ($i = 0; $i < $link->attributes->length; ++$i) {
        $node = $link->attributes->item($i);
        if ($node->nodeName == "href") {
            $attrs[$node->nodeName][$href_count] = $node->nodeValue;
            $href_count++;
            if ($href_count >= 2) {
                echo "A second href has been found";
            }
        }
    }

    echo "<pre>";
    var_dump($attrs);
    echo "</pre>";
}

正如您所预料的那样,遗憾的是它不起作用,在这种情况下,我不会在这里寻求帮助......

请不要犹豫,分享您的知识,我们将非常感谢您的帮助或建议!

更新

我忘记在我的初步问题中指出答案应该仍然允许捕获标准href。我的目标是&#34;延伸&#34;或&#34;改善&#34;我的实际html解析器,以确保我也从任何href检索网址。我的初始代码只使用了RegEx,我无法从嵌套的#34; a&#34;中捕获第二个href。标签。一个完美的答案将允许捕获嵌套和标准href。 Brandon White的解决方案仅适用于嵌套href,但使用两个不同的RegEx(嵌套/标准)来解析整个html内容两次会消耗资源。一个理想的解决方案是RegEx允许同时捕获两者,如果可能的话。

2 个答案:

答案 0 :(得分:1)

你可以用一些漂亮的RegEx来实际做你想要的。使用 Negative Lookahead 和一些逻辑,您实际上可以完全提取嵌套的href位置。

实施例

$result = <<<HTML
<a href="SOME_URL">
    <a href="SOME_URL_2">
    </a>
</a>

<a href="SOME_URL3">
    <a href="SOME_URL_4">
    </a>
</a>

<a href="SOME_URL5">
</a>
<a href="SOME_URL_6">
</a>

HTML;

preg_match_all('/<a.*>(?!<\/a>)\s*<a.*href\s*=\s*"(.+)"/', $result, $matches);

var_dump($matches);

说明

RegEx在这些棘手的情况下非常方便。谢天谢地,您没有必要考虑上面尝试的所有逻辑。您需要的只是RegEx的一些逻辑和知识。我一直推荐的网站是RegExr。分析和构建有效的RegEx非常有用。实际上,这是示例的RegEx "Fiddle"

  • <a.*>这匹配任何第一个锚标记
  • (?!<\/a>)这是一个否定前瞻 - 它会检查以确保后面有 NOT 结束锚标记。这确保它是嵌套的锚匹配。
  • \s*匹配两个锚点之间的任何可能的空白区域。
  • <a.*href\s*=\s*"(.+)"这匹配使用href属性和=之间的任何可能空格和值编写的第二个锚标记。此外,(.+)将网址放入捕获组。使用preg_match_all()函数,它将是$match数组中的第二行。请参阅下面的示例输出。
  • 另请注意,它不会提取上面代码示例中显示的非嵌套网址。

代码输出

Output of Code example above

答案 1 :(得分:1)

我已经能够使用以下解决方案实现目标:

$result = <<<HTML
<a href="SOME_URL">
    <a href="SOME_URL_2">
    </a>
</a>

<a href="SOME_URL3">
    <a href="SOME_URL_4">
    </a>
</a>

<a href="SOME_URL_5">
</a>
<a href="SOME_URL_6">
</a>

HTML;

$dom = new DOMDocument();
@$dom->loadHTML($result);


foreach($dom->getElementsByTagName('a') as $link) {

    $tag_html = $dom->saveHTML($link); //Get tag inner html

    if (substr_count($tag_html, "href") > 1) { //If tag contains more than one href attribute
        preg_match_all('/href="([^"]*)"/is', $tag_html, $link_output, PREG_SET_ORDER);
        $output[] = $link_output[1][1]; //Output second href
    } else { //Not nested tag
        $output[] = $link->getAttribute('href'); //Output first href
    }
}

echo "<pre>".print_r($output)."</pre>";

<强>输出:

array
(
    [0] => SOME_URL_2
    [1] => SOME_URL_4
    [2] => SOME_URL_5
    [3] => SOME_URL_6
)

此解决方案适用于具有混合和/或嵌套内容的整个html页面。它允许根据需要捕获尽可能多的嵌套href,同时仍然捕获标准href&#34; a&#34;标签。