5

从包含大量 HTML 的字符串中,如何将<h1><h2>etc标签中的所有文本提取到新变量中?

我想从这些元素中捕获所有文本并将它们作为逗号分隔值存储在一个新变量中。

可以使用preg_match_all()吗?

4

7 回答 7

6

首先,您需要使用 tidy 清理 HTML(示例中为 $html_str):

$tidy_config = array(
    "indent"               => true,
    "output-xml"           => true,
    "output-xhtml"         => false,
    "drop-empty-paras"     => false,
    "hide-comments"        => true,
    "numeric-entities"     => true,
    "doctype"              => "omit",
    "char-encoding"        => "utf8",
    "repeated-attributes"  => "keep-last"
);

$xml_str = tidy_repair_string($html_str, $tidy_config);

然后您可以将 XML ($xml_str) 加载到 DOMDocument 中:

$doc = DOMDocument::loadXML($xml_str);

最后你可以使用 Horia Dragomir 的方法:

$list = $doc->getElementsByTagName("h1");
for ($i = 0; $i < $list->length; $i++) {
    print($list->item($i)->nodeValue . "<br/>\n");
}

或者您也可以使用 XPath 对 DOMDocument 进行更复杂的查询(参见http://www.php.net/manual/en/class.domxpath.php

$xpath = new DOMXPath($doc);
$list = $xpath->evaluate("//h1");
于 2010-01-14T14:53:21.610 回答
3

还请考虑原生DOMDocumentphp 类。

您可以使用$domdoc->getElementsByTagName('h1')来获取您的标题。

于 2010-01-14T14:44:19.413 回答
3

我知道这是一篇超级旧的帖子,但是我想提一下我能够集体抓取标题标签的最佳方式。

<h1>title</h1> and <h2>title 2</h2>

此方法(用作正则表达式,但 PHP 的行为有点不同。)

/<\s*h[1-2](?:.*)>(.*)</\s*h/i

在你的 preg_match 中使用它

|<\s*h[1-2](?:.*)>(.*)</\s*h|Ui

$group[1]将包括标题标签之间的内容。 $group[0]就是一切<h1>test</h

这将占空间,如果有人添加“class/id”

<h1 class="classname">test</h1>

类/id(组)被忽略。

注意:当我分析 HTML 标记时,我总是将所有空格、换行符、制表符等删除并替换为 1 个空格。这最大限度地减少了多行、dotalls ......以及非常大量的空白,在某些情况下可能会混淆正则表达式格式。

  • 当然,我只抓取 1-2 个标题标签,将其更改为 0-9 即可全部抓取。
  • 如果其他人有要添加的 mod 或修复我的代码,请回复,我真的很想知道。
  • 相反,正则表达式不适合 HTML,这是一个非常开放的论点。因为如果您设计您的 php 函数和正则表达式以完美地去除垃圾并为正则表达式特定表达式准备 html,您将完全能够获取您正在寻找的内容。您可以制作足够的正则表达式函数来替换业余 html 工作。

这是测试页面正则表达式测试的链接

于 2012-09-23T18:46:58.327 回答
2

建议不要对这项工作使用正则表达式并使用SimpleHTMLDOM 解析器

于 2010-01-14T14:34:40.853 回答
2

您可能更适合使用 HTML 解析器。但对于非常简单的场景,这样的事情可能会做:

if (preg_match_all('/<h\d>([^<]*)<\/h\d>/iU', $str, $matches)) {
    // $matches contains all instances of h1-h6
}
于 2010-01-14T14:37:42.843 回答
2

如果你真的想使用正则表达式,我认为:

preg_match_all('/<h[0-6]>([^</h[0-6]>*)</h/i', $string, $matches);

只要您的标题标签没有嵌套,就应该可以工作。正如其他人所说,如果您无法控制 HTML,则正则表达式不是执行此操作的好方法。

于 2010-01-14T14:38:24.823 回答
1

我只想分享我的解决方案:

function get_all_headings( $content ) {
    preg_match_all( '/\<(h[1-6])\>(.*)<\/h[1-6]>/i', $content, $matches );

    $r = array();
    if( !empty( $matches[1] ) && !empty( $matches[2] ) ){
        $tags = $matches[1];
        $titles = $matches[2];
        foreach ($tags as $i => $tag) {
            $r[] = array( 'tag' => $tag, 'title' => $titles[ $i ] );
        }
    }

    return $r;
}

如果找不到标题或类似的东西,此函数将返回一个空数组:

array (
    array (
        'tag' => 'h1',
        'title' => 'This is a title',
    ),
    array (
        'tag' => 'h2',
        'title' => 'This is the second title',
    ),
)
于 2017-06-19T21:13:43.070 回答