【问题标题】:Extracting the body text of an HTML document using PHP使用 PHP 提取 HTML 文档的正文
【发布时间】:2011-06-22 02:39:40
【问题描述】:

我知道为此目的最好使用 DOM,但让我们尝试以这种方式提取文本:

<?php


$html=<<<EOD
<html>
<head>
</head>
<body>
<p>Some text</p>
</body>
</html>
EOD;


        preg_match('/<body.*?>/', $html, $matches, PREG_OFFSET_CAPTURE);

        if (empty($matches))
            exit;

        $matched_body_start_tag = $matches[0][0];
        $index_of_body_start_tag = $matches[0][1];

        $index_of_body_end_tag = strpos($html, '</body>');


        $body = substr(
                        $html,
                        $index_of_body_start_tag + strlen($matched_body_start_tag),
                        $index_of_body_end_tag - $index_of_body_start_tag + strlen($matched_body_start_tag)
        );

echo $body;

结果可以在这里看到:http://ideone.com/vH2FZ

如您所见,我收到的文本比预期的要多。

有一些我不明白的地方,为了获得 substr($string, $start, $length) 函数的正确长度,我正在使用:

$index_of_body_end_tag - $index_of_body_start_tag + strlen($matched_body_start_tag)

我看不出这个公式有什么问题。

有人可以提出问题出在哪里吗?

非常感谢大家。

编辑:

非常感谢大家。我脑子里只有一个错误。看完你的回答,我现在明白问题出在哪里了,应该是:

  $index_of_body_end_tag - ($index_of_body_start_tag + strlen($matched_body_start_tag));

或者:

  $index_of_body_end_tag - $index_of_body_start_tag - strlen($matched_body_start_tag);

【问题讨论】:

  • 我看了你的评论,问题是你有换行,在计算字符时,\n(或\r\n)也被计算在内,所以你的偏移量不正确,这就是你的原因最后阅读更多文字。我会用更好的解释更新我的答案。

标签: php regex text text-processing html-content-extraction


【解决方案1】:

问题是您的字符串在 .在模式中只匹配单行,你需要添加 /s 修饰符到 make 。匹配多行

这是我的解决方案,我更喜欢这种方式。

<?php

$html=<<<EOD
<html>
<head>
</head>
<body buu="grger"     ga="Gag">
<p>Some text</p>
</body>
</html>
EOD;

    // get anything between <body> and </body> where <body can="have_as many" attributes="as required">
    if (preg_match('/(?:<body[^>]*>)(.*)<\/body>/isU', $html, $matches)) {
        $body = $matches[1];
    }
    // outputing all matches for debugging purposes
    var_dump($matches);
?>

编辑:我正在更新我的答案,以便更好地解释您的代码失败的原因。

你有这个字符串:

<html>
<head>
</head>
<body>
<p>Some text</p>
</body>
</html>

一切似乎都很好,但实际上每一行都有非打印字符(换行符)。 您有 53 个可打印字符和 7 个不可打印字符(新行,\n == 每个新行实际上有 2 个字符)。

当你到达这部分代码时:

$index_of_body_end_tag = strpos($html, '</body>');

您得到了

【解决方案2】:

就我个人而言,我不会使用正则表达式。

<?php

$html = <<<EOD

<html>
    <head>
        <title>Example</title>
    </head>
    <body>
        <h1>foobar</h1>
    </body>
</html>

EOD;

$s = strpos($html, '<body>') + strlen('<body>');
$f = '</body>';

echo trim(substr($html, $s, strpos($html, $f) - $s));

?>

返回&lt;h1&gt;foobar&lt;/h1&gt;

【讨论】:

  • 注意:仅当 没有属性(例如:类、样式、事件)时有效
【解决方案3】:

问题在于您的 substr 计算结束索引。你应该一直减去:

$index_of_body_end_tag - $index_of_body_start_tag - strlen($matched_body_start_tag)

但你正在做:

+ strlen($matched_body_start_tag)

也就是说,考虑到您可以使用preg_match only 来做到这一点,这似乎有点矫枉过正。您只需要使用 s 修饰符确保您匹配新行:

preg_match('/<body[^>]*>(.*?)<\/body>/s', $html, $matches);
echo $matches[1];

输出:

<p>Some text</p>

【讨论】:

  • 非常感谢您的回答。您的解决方案简洁明了,但我真的需要知道代码出了什么问题。
  • 我真的认为这与换行符有关。非常感谢您指出问题。
【解决方案4】:

可能有人已经发现了您的错误,我没有阅读所有回复。
代数错了。

code is here

btw,第一次看到ideone.com,这很酷。

$body = substr( 
          $html, 
          $index_of_body_start_tag + strlen($matched_body_start_tag),
          $index_of_body_end_tag - ($index_of_body_start_tag + strlen($matched_body_start_tag))
        );

或..

$body = substr(
          $html,
          $index_of_body_start_tag + strlen($matched_body_start_tag),
          $index_of_body_end_tag - $index_of_body_start_tag - strlen($matched_body_start_tag)
       );

【讨论】:

    猜你喜欢
    • 2017-10-18
    • 2016-11-11
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 2023-03-14
    • 2013-01-21
    • 2011-07-07
    • 1970-01-01
    相关资源
    最近更新 更多