Regex:HTMLドキュメントから読み取り可能な(非コード)テキストとURLを抽出する

StackOverflow https://stackoverflow.com/questions/3951485

質問

入力としてURLを取り、ページのHTMLコンテンツをWebから取得して抽出するアプリケーションを作成しています タグに含まれていないすべて. 。言い換えれば、そのページへの訪問者に見られるように、ページのテキストコンテンツ。これには、カプセル化されたすべてのものを「マスキング」することが含まれます <script></script>, <style></style><!-- -->, 、これらの部分には、タグに包まれていないテキストが含まれているためです(ただし、単独で残っておくのが最適です)。

私はこの正規表現を構築しました:

(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>)

無視したいすべてのコンテンツを正しく選択し、ページのテキストコンテンツのみを残します。ただし、それは私が抽出したいものがマッチコレクションに表示されないことを意味します(Visual Studio 2010でVB.NETを使用しています)。

このようなドキュメント全体のマッチングを「反転」する方法はありますか。そのため、上記のregexのマッチングによって取り残されたすべてのテキスト文字列に一致しますか?

これまでのところ、私がしたことは、最後に別の代替案を追加することでした。これは、「<または>を含まないシーケンス」を選択し、残りのテキストを意味します。私はその最後のビットをキャプチャグループに命名し、試合を反復すると、「テキスト」グループにテキストが存在することを確認します。これは機能しますが、Regexと ただ プレーンテキストの一致が終了します。

これは、HTMLで特定のタグを知らずに、一般的に機能することになっています。抽出することになっています すべて 文章。さらに、ページがすべてのリンクとスクリプトを保持するように元のHTMLを保持する必要があります。タグ、属性を「名前変更」することを恐れることなく、検索と交換を実行できるようにテキストを抽出できるようにするだけが必要です。またはスクリプト変数など(したがって、私が得るすべてのマッチで「何も置き換えて」を実行することはできません。なぜなら、私が必要なものを残しているにもかかわらず、それを再挿入するのは面倒だからです完全に機能するドキュメント)。

Regexを使用してこれが可能であるかどうかを知りたいと思います(そして、HTML Agility PackとXPathについて知っていますが、気分はありません)。

助言がありますか?

アップデート:これが(正規表現ベースの)ソリューションです。 http://www.martinwardener.com/regex/, 、デモWebアプリケーションに実装されているテストエンジンと、オンラインHTMLページで解析を実行できるテストエンジンの両方を表示し、解析時間を与え、結果を抽出しました(リンク、URL、テキストの部分は個別に - 同様に、すべての正規表現の一致が完全なHTMLドキュメントで強調されているビュー)。

役に立ちましたか?

解決 5

さて、これが私がそれをしている方法です:

私の元の正規表現を使用して(タグ検索が完了した後に残されたテキストであるプレーンテキストの検索パターンが追加されました):

(?:(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?P<text>[^<>]*)

その後、vb.netで:

Dim regexText As New Regex("(?:(?:<(?<tag>script|style)[\s\S]*?</\k<tag>>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?<text>[^<>]*)", RegexOptions.IgnoreCase)
Dim source As String = File.ReadAllText("html.txt")
Dim evaluator As New MatchEvaluator(AddressOf MatchEvalFunction)
Dim newHtml As String = regexText.Replace(source, evaluator)

テキストの実際の交換はここで起こります:

Private Function MatchEvalFunction(ByVal match As Match) As String
    Dim plainText As String = match.Groups("text").Value
    If plainText IsNot Nothing AndAlso plainText <> "" Then
        MatchEvalFunction = match.Value.Replace(plainText, plainText.Replace("Original word", "Replacement word"))
    Else
        MatchEvalFunction = match.Value
    End If
End Function

出来上がり。 newHtml ページ内の「オリジナルワード」のすべての発生(ブラウザで表示されているように)が「置換ワード」で切り替えられ、すべてのHTMLとスクリプトコードが触れられない保存されていることを除いて、オリジナルの正確なコピーが含まれるようになりました。もちろん、より精巧な代替ルーチンを入れることができますが、これは基本原則を示しています。これは、関数宣言やHTMLコードなどのロードを含む12行のコードです。比較のためにDOMなどで行われる並列ソリューションを見ることに非常に興味があります(このアプローチはバランスを崩すことができます。 特定 いくつかのネストされたタグの癖の発生 - スクリプトの書き換え - しかし、その損害はまだ非常に限られています(上記のコメントの一部を参照)。

他のヒント

私がしたことは、最後に別の代替手段を追加することでした。 < また >「それは残りのテキストを意味します。私はその最後のビットをキャプチャグループに命名し、試合を反復すると、「テキスト」グループにテキストが存在することを確認します。

それが通常することです。またはさらに簡単に、マークアップパターンのすべての一致を交換し、空の文字列に置き換えてください。残っているのはあなたが探しているものです。

それは一種の作品ですが、あちこちに文字列があり、それが拾われるべきではないようです。

ええ、それはあなたの表現、そして一般的に正規表現が、実際のウェブにある恐怖は言うまでもなく、有効なHTMLさえ解析するのが不十分だからです。あなたが本当にこの無駄なアプローチを追いかけたい場合、最初に見るヒント:属性値(および一般的なテキストコンテンツ)には、覆い隠されていない場合があります > キャラクター。

HTML Agility Packの利点をもう一度提案したいと思います。

ETA:あなたがそれを望んでいるように見えるので、ここにあなたの表現をつまずかせるように見えるマークアップの例があります。

<a href=link></a> - unquoted
<a href= link></a> - unquoted, space at front matched but then required at back
<a href="~/link"></a> - very common URL char missing in group
<a href="link$!*'link"></a> - more URL chars missing in group
<a href=lïnk></a> - IRI
<a href
    ="link"> - newline (or tab)
<div style="background-image: url(link);"> - unquoted
<div style="background-image: url( 'link' );"> - spaced
<div style="background-image: u&#114;l('link');"> - html escape
<div style="background-image: ur\l('link');"> - css escape
<div style="background-image: url('link\')link');"> - css escape
<div style="background-image: url(\
'link')"> - CSS folding
<div style="background-image: url
('link')"> - newline (or tab)

そして、それは完全に有効なマークアップです しない 適切なリンクを一致させます。リンクと一致するしかありません。マークアップ、またはテキストからマークアップを分割する他の手法に関する多くの問題のいずれかではありません。これは氷山の先端です。

Regexは、HTMLドキュメントのテキストコンテンツを取得するために信頼できません。 Regexはネストされたタグを処理できません。ドキュメントにネストされたタグが含まれていないと仮定すると、Regexにはすべてのタグが適切に閉じられている必要があります。

PHPを使用している場合は、簡単にするために、DOM(Document Object Model)を使用してHTMLドキュメントを解析/抽出することを強くお勧めします。通常、DOMライブラリはすべてのプログラミング言語に存在します。

正規表現と一致しない文字列の部分を抽出したい場合は、単にパーツを置き換えることができます。 それは 同じ効果のために空の文字列と一致します。

これが機能する唯一の理由は、あなたが削除することに興味があるタグが <script><style> タグは、ネストできません。

しかし、それは珍しいことではありません <script> プログラムで別のものをプログラム的に追加するコードを含むタグ <script> タグ、その場合、正規表現が失敗します。また、タグが適切に閉じられていない場合にも失敗します。

HTMLを正規表現で解析することはできません。

通常の表現でHTMLを解析すると、悲しみが生じます。

私はあなたがただ楽しみのためにそれをしていることを知っていますが、実際に正しい方法で解析することを行い、確実にそれを行い、テストされているよりも多くのパッケージがそこにあります。

車輪を再発明してはいけません。そして、あなたを将来的にイライラさせることを保証するすべての方法でそれを行う。

ご参考までに、

jQueryを使用して、正規表現の代わりに、HTMLマークアップからテキストのみを抽出することができます。そのためには、次のパターンを使用できます。

$("<div/>").html("#elementId").text()

これを参照できます jsfiddle

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top