[英]PHP - Parse html to retrieve href from an “a” tag that is inside an other “a” tag
我一直在搜索数小时(不应有任何重复),并尝试使用正则表达式(正则表达式)和DOMdocument的许多不同方式,但均未成功。
非标准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>
现在的问题是我正在尝试获取URL“ SOME_URL_3”,并且在使用正则表达式或DOMdocument进行解析时,一旦遇到第一个href,粘贴就会停止。 当然,由于第二个“ a”标记是第一个标记的一部分,因此解析器只会将其视为一个标记。
我观察到,浏览器似乎在解析时会自动将标签分开,如下所示:
之前:
<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。 我的目标是“扩展”或“改进”我的实际html解析器,以确保我也从任何href中检索了这些url。 我的初始代码仅使用RegEx,但无法从嵌套的“ a”标签捕获第二个href。 一个完美的答案将允许捕获嵌套的和标准的href。 布兰登·怀特(Brandon White)的解决方案仅适用于嵌套href,但是使用两个不同的RegEx(嵌套/标准)将整个html内容解析两次会很费资源。 理想的解决方案是RegEx,如果可能的话,它可以同时捕获两者。
实际上,您可以使用一些精美的RegEx来完成您要问的事情。 使用负前瞻和某些逻辑,您实际上可以完全提取嵌套的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“提琴”的示例。
<a.*>
这与任何第一个锚标记匹配 (?!<\\/a>)
这是一个否定的超前行为 -它检查以确保后面没有结束的锚标记。 这确保它是嵌套的锚匹配。 \\s*
匹配两个锚点之间任何可能的空格。 <a.*href\\s*=\\s*"(.+)"
与第二个锚标记匹配,在href属性和=
和值之间使用任何可能的空格写入。 同样, (.+)
将URL放入捕获组 。 使用preg_match_all()
函数,它将是$match
数组中的第二行。 请参阅下面的示例输出。 我已经可以使用以下解决方案实现目标:
$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“ a”标签。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.