6

我维护一个带有 HTML 格式的文章数据库。不幸的是,写文章的编辑不知道正确的 HTML,所以他们经常写这样的东西:

<div class="highlight"><html><head></head><body><p>Note that ...</p></html></div>

我尝试使用HTML::TreeBuilder来解析这个 HTML,但是在解析它并转储生成的树之后,之间的所有元素<div class="highlight">...</div>都消失了。我只剩下<div class="highlight"></div>.

编辑们也经常做以下事情:

<div class="article"><style>@font-face {   font-family: "Cambria"; }</style>Article starts here</div>

解析这个HTML::TreeBuilder结果再次为空<div class="article"></div>

任何想法如何处理这个破碎的 HTML 并真正理解它?

4

4 回答 4

11

我会首先通过HTML::Tidy运行它:

#!/usr/bin/env perl

use strict; use warnings;
use HTML::Tidy;

my $html = <<EO_HTML;
<div class="highlight"><html><head></head>
<body><p>Note that ...</p></html>
</div>
EO_HTML

my $tidy = HTML::Tidy->new;

print $tidy->clean( $html );

输出:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta name="generator" content="tidyp for Windows (v1.04), see www.w3.org">
<title></title>
</head>
<body>
<div class="highlight">
<p>Note that ...</p>
</div>
</body>
</html>

您可以通过设置各种配置选项来控制输出。

然后,通过解析器提供清理后的 HTML。

否则,您可以尝试使用HTML::TokeParser::Simple或什至仅使用HTML::Parser一步一步地构建树,但我相信这种方式很疯狂。

请记住,尝试构建树表示的解析器将比仅识别所看到的各种元素的流解析器更严格。

于 2012-07-04T22:30:37.370 回答
3

您可以尝试使用Marpa::HTML,它是一种高级 HTML 解析器,允许非常自由的解析。它甚至可以使用作者称为ruby​​ slippers的技术解析无效的 HTML ;Marpa::HTML 添加了应该存在的元素。

请参阅Marpa 解析器和 Marpa::HTML 的作者 Jeffrey Kegler如何解析 HTML博客文章中的重新格式化、美化和使无效 HTML 示例有效的示例。

于 2012-07-08T09:38:29.863 回答
1

如果使用得当, XML::LibXML也可能令人惊讶地擅长这种清理工作。它也非常快;一旦你超越了它的学习曲线,它就会变得深入/灵活。

#!/usr/bin/env perl
use strictures;
use XML::LibXML;

my @craptastic = ( '<div class="article"><style>@font-face{ font-family: "Cambria" }</style>Article starts here</div>',
                   '<div class="highlight"><html><head></head><body><p>Note that ...</p></html></div>' );

# The inline setting of recover_silently is broken/non-functional so
# we do the method calls to set.
my $parser = XML::LibXML->new();
$parser->recover_silently(1);
$parser->keep_blanks(1);

for my $crap ( @craptastic )
{
    my $doc = $parser->load_html( string => $crap );

    # Optional example for killing style tags not in the <head/>
    $_->parentNode->removeChild($_) for $doc->findnodes("//body//style");

    print $/, $crap, $/;
    my ( $body ) = $doc->findnodes("//body");
    print "-" x 60, $/;
    print $_->serialize(1) for $body->childNodes;
    print $/, $/;
}

给你-

<div class="article"><style>@font-face{ font-family: "Cambria" }</style>Article starts here</div>
------------------------------------------------------------
<div class="article">Article starts here</div>


<div class="highlight"><html><head></head><body><p>Note that ...</p></html></div>
------------------------------------------------------------
<div class="highlight">
  <p>Note that ...</p>
</div>
于 2012-07-05T15:54:41.897 回答
-1

听起来像标签汤。作为另一种方法,您还可以在 perl 程序中使用 java 程序“ html-tagsoup ”(例如,使用反引号)。它可以像这样被称为独立程序。

java -jar tagsoup-1.2.1 [option ...] [file ...]

我认为 HTML::Tidy 曾经更好或更灵活。

于 2012-07-05T07:50:04.033 回答