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だけを使用して、一度に1ステップずつツリーを構築してみることができますが、その方法は狂気にあると思います。

ツリー表現を構築しようとするパーサーは、さまざまな要素を認識したときにそれを認識するだけのストリームパーサーよりも厳密になることに注意してください。

于 2012-07-04T22:30:37.370 に答える
3

高レベルのHTMLパーサーであるMarpa::HTMLの使用を試みることができ、非常に自由な構文解析が可能になります。作者によるルビースリッパと呼ばれる手法を使用して、無効なHTMLでも解析できます。Marpa :: HTMLは、そこにあるはずの要素を追加します。

MarpaパーサーとMarpa::HTMLの作成者であるJeffreyKeglerによる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 に答える