PHP - 解析 html 以从另一个 "a" 标签内的 "a" 标签检索 href
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 进行解析时,pasing 在遇到第一个 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。我的目标是 "extend" 或 "improve" 我的实际 html 解析器以确保我也从任何 href 检索 urls。我的初始代码仅使用 RegEx,我无法从嵌套的 "a" 标签中捕获第二个 href。一个完美的答案将允许捕获嵌套和标准 href。 Brandon White 的解决方案仅适用于嵌套 href,但使用两个不同的 RegEx (nested/standard) 来解析整个 html 内容两次会消耗资源。如果可能的话,一个理想的解决方案是允许同时捕获两者的 RegEx。
您实际上可以使用一些非常漂亮的 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. It is very helpful to analyze and build working RegEx. In fact, here is a RegEx "Fiddle"。
<a.*>
这匹配任何第一个锚标签
(?!<\/a>)
这是一个 negative lookahead - 检查以确保后面有 NOT 结束锚标记。这确保它是嵌套锚点匹配。
\s*
匹配两个锚点之间任何可能的白色-space。
<a.*href\s*=\s*"(.+)"
这与在 href 属性和 =
和值之间使用任何可能的 space 编写的第二个锚标记相匹配。此外,(.+)
将 URL 放入 捕获组 。使用 preg_match_all()
函数,它将成为 $match
数组中的第二行。请参阅下面的示例输出。
- 另请注意,它不会提取上面代码示例中所示的非嵌套 URL。
代码输出
我已经能够使用以下解决方案实现我的目标:
$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
)
此解决方案适用于具有混合 and/or 嵌套内容的整个 html 页面。它允许根据需要捕获尽可能多的嵌套 href,同时仍然捕获标准 href "a" 标签。
我已经搜索了几个小时(不应该有任何重复)并尝试了多种使用正则表达式(正则表达式)和 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 进行解析时,pasing 在遇到第一个 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。我的目标是 "extend" 或 "improve" 我的实际 html 解析器以确保我也从任何 href 检索 urls。我的初始代码仅使用 RegEx,我无法从嵌套的 "a" 标签中捕获第二个 href。一个完美的答案将允许捕获嵌套和标准 href。 Brandon White 的解决方案仅适用于嵌套 href,但使用两个不同的 RegEx (nested/standard) 来解析整个 html 内容两次会消耗资源。如果可能的话,一个理想的解决方案是允许同时捕获两者的 RegEx。
您实际上可以使用一些非常漂亮的 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. It is very helpful to analyze and build working RegEx. In fact, here is a RegEx "Fiddle"。
<a.*>
这匹配任何第一个锚标签(?!<\/a>)
这是一个 negative lookahead - 检查以确保后面有 NOT 结束锚标记。这确保它是嵌套锚点匹配。\s*
匹配两个锚点之间任何可能的白色-space。<a.*href\s*=\s*"(.+)"
这与在 href 属性和=
和值之间使用任何可能的 space 编写的第二个锚标记相匹配。此外,(.+)
将 URL 放入 捕获组 。使用preg_match_all()
函数,它将成为$match
数组中的第二行。请参阅下面的示例输出。- 另请注意,它不会提取上面代码示例中所示的非嵌套 URL。
代码输出
我已经能够使用以下解决方案实现我的目标:
$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
)
此解决方案适用于具有混合 and/or 嵌套内容的整个 html 页面。它允许根据需要捕获尽可能多的嵌套 href,同时仍然捕获标准 href "a" 标签。