1

我正在使用正则表达式从网页获取 URL。

在本地主机上(带有 Suhosin-Patch (cli) 的 PHP 5.3.15(内置:2012 年 8 月 24 日 17:45:44))代码:

$file = file_get_contents("http://www.etech.haw-hamburg.de/Stundenplan/");
$pattern = "/<a href=\"([^\"]*.pdf)\">(.*)<\/a>/iU";
preg_match_all($pattern, $file, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";

给出:

=> Array
(
        [0] => Sem_IuE_E1a.pdf
        [1] => Sem_IuE_E2a.pdf
        [2] => Sem_IuE_E3a.pdf
        [3] => Sem_IuE_E4a.pdf
        [4] => Sem_IuE_E6AT.pdf
        [5] => Sem_IuE_E7.pdf
        [6] => Sem_IuE_E1b.pdf
        [7] => Sem_IuE_E2b.pdf
        [8] => Sem_IuE_E3b.pdf
        [9] => Sem_IuE_E4b.pdf
        [10] => Sem_IuE_E6II.pdf
        [11] => Sem_IuE_E6KT.pdf
        [12] => Sem_IuE_BMT1.pdf
        [13] => Laborplan%20BMT1%20KoP%201.pdf
        [14] => Sem_IuE_BMT2.pdf
        [15] => Sem_IuE_BMT3.pdf
        [16] => Sem_IuE_BMT4.pdf
        [17] => Sem_IuE_BMT5.pdf
        [18] => Sem_IuE_BMT6.pdf
        [19] => Sem_IuE_IE2.pdf
        [20] => Sem_IuE_IE4.pdf
        [21] => Sem_IuE_IE6.pdf
        [22] => Sem_IuE_AM.pdf
        [23] => Sem_IuE_IKM1.pdf
        [24] => Legende_Stud.pdf
        [25] => Kalender.pdf
        [26] => Doz.pdf
        [27] => Doz.pdf
    )

同时,在远程服务器(PHP 5.3.3(cli)(构建:2013 年 2 月 22 日 02:51:11))上,相同的代码给出:

=> Array
    (
        [0] => Sem_IuE_E2a.pdf
        [1] => Sem_IuE_E7.pdf
        [2] => Sem_IuE_E1b.pdf
        [3] => Sem_IuE_E2b.pdf
        [4] => Sem_IuE_E3b.pdf
        [5] => Sem_IuE_E6II.pdf
        [6] => Sem_IuE_E6KT.pdf
        [7] => Sem_IuE_BMT1.pdf
        [8] => Laborplan%20BMT1%20KoP%201.pdf
        [9] => Sem_IuE_BMT2.pdf
        [10] => Sem_IuE_BMT3.pdf
        [11] => Sem_IuE_BMT4.pdf
        [12] => Sem_IuE_BMT5.pdf
        [13] => Sem_IuE_BMT6.pdf
        [14] => Sem_IuE_IE2.pdf
        [15] => Sem_IuE_IE4.pdf
        [16] => Sem_IuE_IE6.pdf
        [17] => Sem_IuE_AM.pdf
        [18] => Doz.pdf
        [19] => Doz.pdf
    )

问题是什么?

4

2 回答 2

1

我没有准确的答案。但是在您的问题中,您提到使用 PHP 5.3.3 和 PHP 5.3.15 会产生不同的结果。

我看了一下PHP5 ChangeLog,答案可能就在哪里,并看到了以下可能的解释。

将捆绑的 PCRE 升级到版本 8.11。(伊利亚)

将捆绑的 PCRE 升级到版本 8.12。(斯科特)

我阅读了两个 PCRE 版本的发行说明,我不确定在你的情况下什么会影响匹配,除了一些提到 UTF8 编码的更正。

但是,在查看U修饰符时,我在PCRE 配置选项中注意到:

PCRE 的回溯限制。对于 PHP < 5.3.7,默认为 100000。

我的猜测是U(PCRE_UNGREEDY) 修饰符中的一些修复改变了两者之间的部分<a>匹配的方式。这是有道理的,因为通过查看您正在抓取的页面的源代码,在早期 PHP 版本中唯一匹配的是<a>不包含内部 HTML 的标签。

例如,这个匹配:

<a href="Sem_IuE_E2a.pdf">E2a</a>

这个没有:

<a href="Sem_IuE_E4a.pdf"><span lang=IT style='mso-ansi-language:IT'>E4a</span></a>

非常有趣,但是如何解决呢?

我无法访问较早的 PHP 版本,因此无法对其进行测试,但我会说删除正则表达式的贪婪部分,因为您不需要匹配<a></a>标签内的部分,因为该值已包含在 PDF 文件名中:

$pattern = "/<a href=\"([^\"]*.pdf)\">/i";

或者

使用DOM 解析器

于 2013-03-25T23:21:40.970 回答
1

我想出了一个解决方法。如果你打开页面,去掉标签,然后解析你应该得到更一致的答案。来自 Microsoft 应用程序(目标页面)的代码非常糟糕。

<?php
$file = file_get_contents("http://www.etech.haw-hamburg.de/Stundenplan/");
$file = strip_tags($file,'<a>');
$pattern = "!\<a href=[\"|']([^.]+\.pdf)[\"|']\>([^\<]+)\<\/a\>!iU";
preg_match_all($pattern, $file, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";
?>
于 2013-03-25T23:33:25.277 回答