1

我正在尝试编写一个正则表达式来从 HTML 源中提取 URL 列表的hrefanchor文本。anchor文本可以是任何值。

HTML部分如下:

<div class="links"><a rel="nofollow" target="_blank" href="http://url1.com" class="get-all">URL1</a><a rel="nofollow" target="_blank" href="http://url2.com" class="get-all">This is Url-2</a><a rel="nofollow" target="_blank" href="http://url3.com" class="get-all">This is Url-3</a><a rel="nofollow" target="_blank" href="http://url4.com" class="get-all">Sweet URL 4</a></div>

我尝试了以下正则表达式,但它不起作用,因为它在</a>标记之前抓取所有内容并失败。

preg_match_('/<a rel="nofollow" target="_blank" href="(.*)" class="see-all">(.*)<\/a>/', $source , $website_array);

提取所需数据的有效正则表达式是什么?

4

4 回答 4

6

如果你一定要知道,这个表达式是贪心的,所以它很可能匹配第一个锚点的开始和最后一个锚点的结束;修饰符将/U修复:

preg_match('/<a rel="nofollow" target="_blank" href="(.*)" class="see-all">(.*)<\/a>/U', $source , $website_array);

请注意,这pcre.backtrack_limit适用于非贪婪模式。

使用前瞻集可能会提供更好的性能:

preg_match('/<a rel="nofollow" target="_blank" href="([^"]*)" class="see-all">([^<]*)<\/a>/', $source , $website_array);

这会给锚本身内部的标签带来麻烦。

由于上述限制,我会认真考虑使用 HTML 解析器:

$d = new DOMDocument;
$d->loadHTML($source);
$xp = new DOMXPath($d);
foreach ($xp->query('//a[@class="see-all"][@rel="nofollow"][@target="_blank"]') as $anchor) {
    $href = $anchor->getAttribute('href');
    $text = $anchor->nodeValue;
}

演示

这将愉快地以不同的顺序处理属性,并使您能够在内部进一步查询等。

于 2013-02-19T23:15:57.650 回答
2

尝试

preg_match_all('/<a[^>]+href="([^"]+)"[^>]*>([^>]+)<\/a>/is', $source , $website_array);

它将匹配所有链接并返回一个包含信息的数组。笔记:

[^"] - 匹配除 " 之外的任何字符

于 2013-02-19T23:16:30.303 回答
1

虽然使用正则表达式解析 HTML 通常是一个坏主意(我建议查看 DOMDocument 类以获得更好的解决方案),但它可以用于某些情况下,您对要提取的内容有一个非常具体的想法,并且可以确保在在所有情况下,该变量文本实际上都不会破坏您的正则表达式。

对于您的情况,您可以尝试:

$pattern = '#<a rel="nofollow" target="_blank" href="(.*)" class="get-all">(.*)</a>#U';
preg_match_all($pattern, $source, $website_array);

请注意末尾的不贪婪修饰符 ( U)。仅匹配可能的最小匹配非常重要。

于 2013-02-19T23:18:21.223 回答
0

或者,您可以这样做:

<?php
$html = <<<HTML
<div class="links"><a rel="nofollow" target="_blank" href="http://url1.com" class="get-all">URL1</a><a rel="nofollow" target="_blank" href="http://url2.com" class="get-all">This is Url-2</a><a rel="nofollow" target="_blank" href="http://url3.com" class="get-all">This is Url-3</a><a rel="nofollow" target="_blank" href="http://url4.com" class="get-all">Sweet URL 4</a></div>
HTML;


$xml = new DOMDocument();
@$xml->loadHTML($html);

$links=array();
$i=0;
//Get all divs
foreach($xml->getElementsByTagName('div') as $divs) {
    //if this div has a class="links"
    if($divs->getAttribute('class')=='links'){
        //loop through this div
        foreach($xml->getElementsByTagName('a') as $a){
            //if this a tag dose not have a class="get-all" continue to next
            if($a->getAttribute('class')!='get-all')
            continue;

            //Assign values to the links array
            $links[$i]['href']=$a->getAttribute('href');
            $links[$i]['value']=$a->nodeValue;
            $i++;
        }

    }
}

print_r($links);
/*
Array
(
    [0] => Array
        (
            [href] => http://url1.com
            [value] => URL1
        )

    [1] => Array
        (
            [href] => http://url2.com
            [value] => This is Url-2
        )

    [2] => Array
        (
            [href] => http://url3.com
            [value] => This is Url-3
        )

    [3] => Array
        (
            [href] => http://url4.com
            [value] => Sweet URL 4
        )

)
*/
?>
于 2013-02-19T23:24:39.813 回答