有一个html代码包含许多href。但我不需要所有的href。我只想得到div中包含的hrefs:
<div class="category-map second-links">
*****
</div> <p class="sec">
我想看到的结果:
<a href='xxx'>yyy</a>
<a href='zzz'>www</a>
...
我的版本(不工作):
(?<=<div class='"category-map second-links'">)(.+?(<a href='".+?".+?>.+<'/a>))+(?=<'/div> <p class="sec">)
免责声明:最好使用合适的html解析器。这个答案是出于教育目的,尽管如果它是有效的html:P,它比常见的正则表达式更可靠
Regex太棒了
所以我决定分两部分来做:
- 匹配
<div class="category-map second-links"></div>
中的所有内容,即使它是嵌套的 - 循环这些匹配,并匹配
<a></a>
,我选择保持简单,因为我不希望链接嵌套
最难的部分
这是正则表达式,我们将使用递归模式和xsi
修饰符:
<div's+class's*='s*"'s*category-map's+second-links's*"'s*> # match a certain div with a certain classes
(?: # non-capturing group
(?:<!--.*?-->)? # Match the comments !
(?:(?!</?div[^>]*>).) # check if there is no start/closing tag
| # or (which means there is)
(?R) # Recurse the pattern, it's the same as (?0)
)* # repeat zero or more times
</div's*> # match the closing tag
(?=.*?<p's+class's*='s*"'s*sec's*"'s*>) # make sure there is <p class="sec"> ahead of the expression
修改器:
s
:使模式中的点元字符与所有字符(包括换行符)匹配x
:模式中的空白数据字符将被完全忽略,除非转义或在字符类内,字符类外未转义的#
和下一个换行符(包括换行符)之间的字符也将被忽略。这相当于Perl的/x
修饰符,可以在复杂的模式中包含注释i
:不区分大小写匹配
简单的部分
如果没有像<a title="</a>"></a>
:这样疯狂的东西,匹配未测试的a
标签并没有那么困难
<a[^>]*> # match the beginning a tag
.*? # match everything ungreedy until ...
</a's*> # match </a > or </a>
# Not forgetting the xsi modifiers
用PHP封装所有内容
$input = '<div class="category-map second-links">
*****
<!--<div class="category-map second-links"> Comment hacks -->
<div class="category-map second-links">
<a href=''xxx''>yyy</a>
<a href=''zzz''>www</a>
...
</div>
<div class="category-map second-links">
*****
<!--<div class="category-map second-links"> Comment hacks -->
<div class="category-map second-links">
<a href=''aaa''>bbb</a>
<a href=''ccc''>ddd</a>
...
</div>
</div> <p class="sec">';
$links = array();
preg_match_all('~
<div's+class's*='s*"'s*category-map's+second-links's*"'s*> # match a certain div with a certain classes
(?: # non-capturing group
(?:<!--.*?-->)? # Match the comments !
(?:(?!</?div[^>]*>).) # check if there is no start/closing tag
| # or (which means there is)
(?R) # Recurse the pattern, it''s the same as (?0)
)* # repeat zero or more times
</div's*> # match the closing tag
(?=.*?<p's+class's*='s*"'s*sec's*"'s*>) # make sure there is <p class="sec"> ahead of the expression
~sxi', $input, $matches);
if(isset($matches[0])){
foreach($matches[0] as $match){
preg_match_all('~
<a[^>]*> # match the beginning a tag
.*? # match everything ungreedy until ...
</a's*> # match </a > or </a>
~isx', $match, $tempLinks);
if(isset($tempLinks[0])){
array_push($links, $tempLinks[0]);
}
}
}
if(isset($links[0])){
print_r($links[0]);
}else{
echo 'empty :(';
}
在线演示
硬质部分简易部件PHP代码
参考文献
- PHP正则表达式修饰符
- 递归模式
- 解释递归模式
如果将HTML加载到DOM文档中,则可以使用Xpath从中查询节点。
文档中的所有a元素:
//a
具有祖先/父div元素的:
//a[ancestor:div]
具有类别属性category-map second-links
//a[ancestor::div[@class = "category-map second-links"]]
获取过滤后的a元素的href属性(可选)
//a[ancestor::div[@class = "category-map second-links"]]/@href
完整示例:
$html = <<<'HTML'
<div class="category-map second-links">
*****
<!--<div class="category-map second-links"> Comment hacks -->
<div class="category-map second-links">
<a href='xxx'>yyy</a>
<a href='zzz'>www</a>
...
</div>
<div class="category-map second-links">
*****
<!--<div class="category-map second-links"> Comment hacks -->
<div class="category-map second-links">
<a href='aaa'>bbb</a>
<a href='ccc'>ddd</a>
...
</div>
</div> <p class="sec">
HTML;
$dom = new DOMDocument();
$dom->loadHtml($html);
$xpath = new DOMXpath($dom);
// fetch the href attributes
$hrefs = array();
foreach ($xpath->evaluate('//a[ancestor::div[@class = "category-map second-links"]]/@href') as $node) {
$hrefs[] = $node->value;
}
var_dump($hrefs);
// fetch the a elements an read some data from them
$linkData = array();
foreach ($xpath->evaluate('//a[ancestor::div[@class = "category-map second-links"]]') as $node) {
$linkData[] = array(
'href' => $node->getAttribute('@href'),
'text' => $node->nodeValue,
);
}
var_dump($linkData);
// fetch the a elements and store their html
$links = array();
foreach ($xpath->evaluate('//a[ancestor::div[@class = "category-map second-links"]]') as $node) {
$links[] = $dom->saveHtml($node);
}
var_dump($links);
使用simpledomhtml
// Create DOM from URL
$html = file_get_html('<YOU_WEBSITE_URL_HERE>');
// Find specific tag
foreach($html->find('div.category-map.second-links a') as $anchor) {
$anchors[] = $anchor;
}
print_r($anchors);
如果您想使用Regex,那么您可能会使用两个Regex查询一个用于获取所有div,另一个用于在每个div中查找href。
因为在像这样的单一查询中
"<div.*?<a href='(?<data>.*?)'.*?</div>"
如果任何div有多个href,则只能得到一个href。
所以你可以使用dom
$dom->find('div a')->attrib('href');
我不确定上面的dom是否100%有效,但我给你这个提示,希望你能为你做一个合适的