从HTML中提取文本的正则表达式

22

我希望从一个常规的HTML页面中提取所有文本(无论是否显示)。

我想要 删除

  • 任何HTML标签
  • 任何JavaScript
  • 任何CSS样式

是否有一个或多个正则表达式可以实现这一点?


请参考 https://dev59.com/tnVD5IYBdhLWcg3wQZQg。 - S.Lott
小心Zalgo。 - Kelly S. French
11个回答

22

移除 JavaScript 和 CSS:

<(script|style).*?</\1>

去除标签

<.*?>

11
“/<(.|\n)*?>/g”将带您进入天堂城市。 - FUD
谢谢,这真的简化了一切! - K3---rnc

14

使用正则表达式无法真正解析HTML。它太复杂了。正则表达式无法正确处理<![CDATA[区段。此外,一些常见的HTML东西,如&lt;text>在浏览器中可以作为正确文本工作,但可能会使一个天真的正则表达式感到困惑。

使用适当的HTML解析器将使您更加愉快和成功。Python用户通常使用Beautiful Soup之类的工具来解析HTML并剥离标签和脚本。


另外,浏览器设计时容忍不规范的HTML。因此,您经常会发现自己尝试解析明显不正确但在浏览器中运行良好的HTML。

您可能能够使用正则表达式解析不良HTML。这只需要耐心和刻苦工作。但使用别人的解析器通常更简单。


一定要使用专门的HTML解析器 - 不要自己造轮子!如果你在使用Ruby,我想建议使用Hpricot。 - Neall
为什么 <text> 会困扰正则表达式?大多数人会将其设置为忽略,这是正确的:它是文本而不是HTML。如果因为它们解析HTML实体(我想这是个好主意),那么你应该在正则表达式之后对文本进行解析,而不是在HTML上进行解析... - Matthew Scharley
4
我的观点不是说这是不可能的。我的观点是,你可以通过使用其他人处理所有边缘情况的解析器来节省大量调试正则表达式的时间。 - S.Lott
+1 但我认为关于格式错误的HTML的观点在这里是无关紧要的,因为我们特意不试图解析HTML,只需使用正则表达式提取任何看起来像标签的内容,而不考虑其结构。 - annakata
@annakata:“提取任何看起来像标签的东西”或多或少是解析。因为HTML是一种比RE设计描述更复杂的语言,所以解析是在HTML中查找任何内容的唯一方法。除了在琐碎的情况下,RE总是会失败。 - S.Lott
BeautifulSoup使用正则表达式解析HTML,因此很容易被欺骗。https://dev59.com/x3VD5IYBdhLWcg3wE3bz - jfs

7

我需要一个(在php中的)正则表达式解决方案,它可以比PHPSimpleDOM更快地返回纯文本。以下是我想出的解决方案:

function plaintext($html)
{
    // remove comments and any content found in the the comment area (strip_tags only removes the actual tags).
    $plaintext = preg_replace('#<!--.*?-->#s', '', $html);

    // put a space between list items (strip_tags just removes the tags).
    $plaintext = preg_replace('#</li>#', ' </li>', $plaintext);

    // remove all script and style tags
    $plaintext = preg_replace('#<(script|style)\b[^>]*>(.*?)</(script|style)>#is', "", $plaintext);

    // remove br tags (missed by strip_tags)
    $plaintext = preg_replace("#<br[^>]*?>#", " ", $plaintext);

    // remove all remaining html
    $plaintext = strip_tags($plaintext);

    return $plaintext;
}

当我在一些复杂的网站上测试时(论坛似乎包含一些难以解析的html),这种方法返回了与PHPSimpleDOM纯文本相同的结果,只是速度快得多。它还正确处理了列表项(li标签),而PHPSimpleDOM没有做到。
至于速度:
- SimpleDom: 0.03248秒。 - RegEx:0.00087秒。 快37倍!

迄今为止最好的解决方案!易于使用!非常感谢! - Joe
你能进一步阐述吗?例如,考虑到 <li >(带有额外的空格)。 - minion

4

如果考虑使用正则表达式来完成这个任务,可能会让人感到困难。您是否考虑过使用XSLT?提取XHTML文档中所有文本节点的XPath表达式,不包括脚本和样式内容,如下:

//body//text()[not(ancestor::script)][not(ancestor::style)]

1
简单而优雅 == 美丽。 - Pablo Fernandez
那可能会起作用,但它也会返回在<script>标签内的文本(即代码)。 - Kibbee
足够正确,见编辑。可能还有其他特殊情况,但这是一般的想法。 - Chris Noe
无法在真实的HTML页面上运行,即HTML格式不正确。大多数XML解析器不支持“真实的HTML”。这就是为什么我过去一直使用HtmlAgilityPack(谷歌搜索)来完成这种类型的任务。 - Ash
确实,这是一个持续的痛点。另一个选择是使用tidy预处理页面。 - Chris Noe

2
简单的HTML最简单的方法(Python示例):
text = "<p>This is my> <strong>example</strong>HTML,<br /> containing tags</p>"
import re
" ".join([t.strip() for t in re.findall(r"<[^>]+>|[^<]+",text) if not '<' in t])

返回这个:
'This is my> example HTML, containing tags'

2
这是一个用于删除即使是最复杂的HTML标签的函数。
function strip_html_tags( $text ) 
{

$text = preg_replace(
    array(
        // Remove invisible content
        '@<head[^>]*?>.*?</head>@siu',
        '@<style[^>]*?>.*?</style>@siu',
        '@<script[^>]*?.*?</script>@siu',
        '@<object[^>]*?.*?</object>@siu',
        '@<embed[^>]*?.*?</embed>@siu',
        '@<applet[^>]*?.*?</applet>@siu',
        '@<noframes[^>]*?.*?</noframes>@siu',
        '@<noscript[^>]*?.*?</noscript>@siu',
        '@<noembed[^>]*?.*?</noembed>@siu',

        // Add line breaks before & after blocks
        '@<((br)|(hr))@iu',
        '@</?((address)|(blockquote)|(center)|(del))@iu',
        '@</?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu',
        '@</?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu',
        '@</?((table)|(th)|(td)|(caption))@iu',
        '@</?((form)|(button)|(fieldset)|(legend)|(input))@iu',
        '@</?((label)|(select)|(optgroup)|(option)|(textarea))@iu',
        '@</?((frameset)|(frame)|(iframe))@iu',
    ),
    array(
        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
        "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0",
        "\n\$0", "\n\$0",
    ),
    $text );

// Remove all remaining tags and comments and return.
return strip_tags( $text );
    }

2

使用Perl语法来定义正则表达式,一个开始的方法可能是:

!<body.*?>(.*)</body>!smi

然后对该组结果应用以下替换:
!<script.*?</script>!!smi
!<[^>]+/[ \t]*>!!smi
!</?([a-z]+).*?>!!smi
/<!--.*?-->//smi

当然,这不会将东西格式化为文本文件,但它可以除去所有的HTML(大多数情况下,可能有一些情况无法正常工作)。更好的方法是在使用语言解析HTML并从中提取文本时使用XML解析器。

1

你不能只使用C#中可用的WebBrowser控件吗?

        System.Windows.Forms.WebBrowser wc = new System.Windows.Forms.WebBrowser();
        wc.DocumentText = "<html><body>blah blah<b>foo</b></body></html>";
        System.Windows.Forms.HtmlDocument h = wc.Document;
        Console.WriteLine(h.Body.InnerText);

1
string decode = System.Web.HttpUtility.HtmlDecode(your_htmlfile.html);
                Regex objRegExp = new Regex("<(.|\n)+?>");
                string replace = objRegExp.Replace(g, "");
                replace = replace.Replace(k, string.Empty);
                replace.Trim("\t\r\n ".ToCharArray());

then take a label and do "label.text=replace;" see on label out put

.


将“g”替换为行代码:string replace = objRegExp.Replace(decode, ""); - mahesh
用代码替换“g”:string replace = objRegExp.Replace(decode, ""); - mahesh

1
如果您使用的是PHP,请尝试在SourceForge上获取的Simple HTML DOM。
否则,Google html2text,并且您将会找到各种针对不同语言的实现,这些实现基本上使用一系列正则表达式来删除所有标记。请注意,由于没有结束标记的标记有时可能会被留下,因此要小心处理,并且要注意特殊字符,例如&(它是&amp;)。
还要注意注释和JavaScript,因为我发现使用正则表达式处理特别麻烦,这就是为什么我通常更喜欢让一个自由解析器来完成所有工作的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接