使用正则表达式解析 HTML 可能不是最好的方法。
您可以查看DOMDocument::loadHTML,它允许您使用 DOM 方法(以及 XPath 查询,如果您知道的话)来处理 HTML 文档。
您可能还想看看Zend_Dom 和Zend_Dom_Query,顺便说一句,如果您可以在您的应用程序中使用Zend Framework 的某些部分,它们会非常好。
例如,在使用 Zend_Test 进行功能测试时,它们用于从 HTML 页面获取数据——并且工作得很好;-)
一开始可能看起来更难...但是,考虑到一些 HTML 页面的混乱,这可能是一个更明智的想法...
在评论和 OP 编辑之后编辑
这里有几个想法,从“简单”的东西开始,一个输入标签:
- 它可以跨多行传播
- 它可以有很多属性
- 您只对名称和值感兴趣,您必须处理这两个可以按任何可能的顺序排列的事实
- 属性的值可以有双引号、单引号,甚至没有任何内容
- 标签/属性既可以是小写也可以是大写
- 标签不必总是关闭
好吧,其中一些点是无效的-HTML;但仍然可以在最常见的网络浏览器中使用,因此必须考虑它们...
只有这些点,我才不想成为编写正则表达式的人^^
但我想可能还有其他我没有想到的困难。
另一方面,你有 DOM 和 xpath...要获取输入 name="q" 的值(例如 this page),这是这样的:
$url = 'http://www.google.fr/search?q=test&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a';
$html = file_get_contents($url);
$dom = new DOMDocument();
if (@$dom->loadHTML($html)) {
// yep, not necessarily valid-html...
$xpath = new DOMXpath($dom);
$nodeList = $xpath->query('//input[@name="q"]');
if ($nodeList->length > 0) {
for ($i=0 ; $i<$nodeList->length ; $i++) {
$node = $nodeList->item($i);
var_dump($node->getAttribute('value'));
}
}
} else {
// too bad...
}
这里有什么重要的? XPath 查询,仅此而已……其中是否有任何静态/常量?
好吧,我说我想要所有<input> 的name 属性等于“q”。
而且它确实有效:我得到了这个结果:
string 'test' (length=4)
string 'test' (length=4)
(我查过:页面上有两个输入name="q" ^^)
我知道页面的结构吗?绝对不是;-)
我只知道我/你/我们想要名为 q 的输入标签;-)
这就是我们得到的 ;-)
编辑 2:选择和选项有点有趣:
好吧,只是为了好玩,这就是我想出的选择和选项:
$url = 'http://www.google.fr/language_tools?hl=fr';
$html = file_get_contents($url);
$dom = new DOMDocument();
if (@$dom->loadHTML($html)) {
// yep, not necessarily valid-html...
$xpath = new DOMXpath($dom);
$nodeListSelects = $xpath->query('//select');
if ($nodeListSelects->length > 0) {
for ($i=0 ; $i<$nodeListSelects->length ; $i++) {
$nodeSelect = $nodeListSelects->item($i);
$name = $nodeSelect->getAttribute('name');
$nodeListOptions = $xpath->query('option[@selected="selected"]', $nodeSelect); // We want options that are inside the current select
if ($nodeListOptions->length > 0) {
for ($j=0 ; $j<$nodeListOptions->length ; $j++) {
$nodeOption = $nodeListOptions->item($j);
$value = $nodeOption->getAttribute('value');
var_dump("name='$name' => value='$value'");
}
}
}
}
} else {
// too bad...
}
我得到一个输出:
string 'name='sl' => value='fr'' (length=23)
string 'name='tl' => value='en'' (length=23)
string 'name='sl' => value='en'' (length=23)
string 'name='tl' => value='fr'' (length=23)
string 'name='sl' => value='en'' (length=23)
string 'name='tl' => value='fr'' (length=23)
这是我所期望的。
一些解释?
嗯,首先,我获取页面的所有选择标签,并将它们的名称保存在内存中。
然后,对于其中的每一个,我都会获得作为其后代的选定选项标签(总是只有一个,顺便说一句)。
在这里,我有价值。
比前面的例子复杂一点...但我相信仍然比正则表达式容易得多...花了我大概 10 分钟,而不是更多...而且我仍然没有勇气(疯狂? )开始考虑某种能够做到这一点的突变正则表达式:-D
哦,顺便说一句:我仍然不知道 HTML 文档的结构是什么样的:我什至没有看过它的源代码 ^^
我希望这可以帮助更多...
谁知道呢,也许我会说服你在解析 HTML 时,正则表达式不是一个好主意......也许吧? ;-)
仍然:玩得开心!