我当然错过了一些明显的东西,因为这非常简单,但这就是我遇到的问题。
在抓取网站时,我正在拉一些格式类似于:
的链接<a href="/test.php?var1=123&var2=456&var3=789">SomeString</a>
虽然有时某些链接看起来像:
<a href="/test.php?var1=123&var2=456&var3=789" title="sometitle">SomeString</a>
使用如下所示的正则表达式,但它添加了我不想要的匹配项:
'/<a href=\"/test.php\?var1=([0-9]+)&var2=([0-9]+)&var3=([0-9]+)\"(^.*?)>(^.*?)<\/a>'
所以很明显我得到了一个我不想要的比赛,但它确实考虑了可能出现的“标题”变量。有没有办法告诉preg_match_all()“这里可能有东西,但你应该忽略它”或者如果它找到它,它匹配它?
感谢。
编辑,因为不清楚:
在我的原始示例中,我想找出var1,var2,var3等于什么,以及和之间的文本(我的例子中的SomeString)。如果我正在浏览一个包含大量结果的页面,偶尔会有一个字符串中的“title =”,这将使我的正则表达式失效。所以我想告诉它“这可能在这里,但不匹配,只是忽略它”。
答案 0 :(得分:3)
请记住,使用正则表达式解析html并不是最好的方法,您可以使用这种更便携的解决方案:
$pattern = <<<'LOD'
~
(?: # open a non-capturing group
<a\s # begining of the a tag
(?: # open a non capturing group
[^h>]+ # all characters but "h" and "<" one or more times
| # OR
\Bh+ # one or more "h" not preceded by a word bundary
| # OR
h(?!ref\b) # "h" not followed by "ref"
)*+ # repeat the group zero or more times
href\s*=\s*"[^?]+\? # href with the begining of the link until the "?"
\K # reset all the match (this part is not needed)
| # OR
\G(?!\A) # a contiguous match
) # close the non-capturing group
(?: # open a non capturing group
(?<key>[^=&]++) # take the key
= # until the "="
(?<value>[^&"]++) # take the value
(?: & | (?=") ) # a "&" or followed by a double quote
| # OR
"[^>]*> # a double quote and the end of the opening tag
(?<content> # open the content named capturing group
(?: # open a non capturing group
[^<]+ # all characters but "<" one or more times
| # OR
<(?!/a\b) # a "<" not followed by "/a" (the closing a tag)
)*+ # repeat the group zero or more times
) # close the named capturing group
</a> # the closing tag (can be removed)
) # close the non-capturing group
~xi
LOD;
这种模式允许以下几点:
它不关心标签
它不关心键/值对的数量(它需要全部)
它忽略了网址
它允许空格(href = "
)
它支持内容部分
但提取结果有点困难:
preg_match_all($pattern, $subject, $matches);
foreach($matches['key'] as $k => $v) {
if (empty($v)) {
$result[] = array('values' => $keyval,
'content' => $matches['content'][$k]);
unset($keyval);
} else {
$keyval[] = array($v => $matches['value'][$k]);
}
}
print_r($result);
这种方式的主要兴趣在于DOM解析器具有与浏览器(也是解析器)类似的行为,因为它不关心属性的数量或位置,简单,双重或不引号和标签之间的内容类型。
$doc = new DOMDocument();
@$doc->loadHTML($yourhtml);
$linkNodeList = $doc->getElementsByTagName("a");
foreach($linkNodeList as $linkNode) {
if (preg_match('~var1=(?<var1>\d+)&var2=(?<var2>\d+)&var3=(?<var3>\d+)~i',
$linkNode->getAttribute('href'), $match)) {
foreach($match as $k => &$v) {
if (is_numeric($k)) unset($v);
}
// take the content between "a" tags
$content= '';
$children = $linkNode->childNodes;
foreach ($children as $child) {
$content .= $child->ownerDocument->saveXML( $child );
}
$result[] = array('values' => $match, 'content' => $content);
}
}
print_r($result);
答案 1 :(得分:1)
这个正则表达式将:
<a\b(?=\s)(?=(?:[^>=]|='[^']*'|="[^"]*"|=[^'"][^\s>]*)*?\shref=(['"]?)\/test.php\?var1=([0-9]+)&var2=([0-9]+)&var3=([0-9]+)\1(?:\s|\/>|>))(?:[^>=]|='[^']*'|="[^"]*"|=[^'"][^\s>]*)*>(.*?)<\/a>
示例文字
请注意mouseover attibute中相当困难的边缘情况
<a onmouseover=' href="/test.php?var1=666&var2=666&var3=666" ; if ( 6 > a ) { funRotate(href) } ; ' href="/test.php?var1=123&var2=456&var3=789" title="sometitle">SomeString</a>
<强>匹配强>
组0从打开到关闭获取整个标签
第1组获取报价,然后在内部使用该报价以确保使用正确的报价来关闭href值
组2-4从var1,var2和var3中获取值
第5组获取<a...>
... </a>
[0][0] = <a onmouseover=' href="/test.php?var1=666&var2=666&var3=666" ; if ( 6 > a ) { funRotate(href) } ; ' href="/test.php?var1=123&var2=456&var3=789" title="sometitle">SomeString</a>
[0][1] = "
[0][2] = 123
[0][3] = 456
[0][4] = 789
[0][5] = SomeString
答案 2 :(得分:0)
您可以使用?
或*
个字符。 ?
被称为非贪婪,但我认为它只是“可选的”。 *
匹配“零或更多”。
您的正则表达式应更改为
'/<a href=\"/test.php?var1=([0-9]+)&var2=([0-9]+)&var3=([0-9]+)\"(^.*?)?>(^.*?)<\/a>'
^
OR
'/<a href=\"/test.php?var1=([0-9]+)&var2=([0-9]+)&var3=([0-9]+)\"(^.*?)*>(^.*?)<\/a>'
^
如果您不想对title="something"
进行分组,那么您可以在正则表达式中使用(?:)
来避免捕获。所以
'/<a href=\"/test.php?var1=([0-9]+)&var2=([0-9]+)&var3=([0-9]+)\"(?:^.*?)*>(^.*?)<\/a>'
^^^^^^^^^
答案 3 :(得分:0)
我认为这应该有效:
^<a\shref=\"\/test.php\?var1=([0-9]+)&var2=([0-9]+)&var3=([0-9]+)\"(?:.*?)>(.*)?<\/a>$
问号应该在正则表达式中转义...否则匹配
<a href="/test.phvar1=123&var2=456&var3=789">SomeString</a>